diff --git a/lib/core/agent.py b/lib/core/agent.py index b3eba4508..98f069110 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -17,6 +17,7 @@ from lib.core.common import isDBMSVersionAtLeast from lib.core.common import isTechniqueAvailable from lib.core.common import randomInt from lib.core.common import randomStr +from lib.core.common import singleTimeWarnMessage from lib.core.convert import urlencode from lib.core.data import conf from lib.core.data import kb @@ -286,11 +287,22 @@ class Agent: if field.startswith("(CASE") or field.startswith("(IIF"): nulledCastedField = field else: - nulledCastedField = queries[Backend.getIdentifiedDbms()].cast.query % field + _ = queries[Backend.getIdentifiedDbms()] + nulledCastedField = _.cast.query % field if Backend.isDbms(DBMS.ACCESS): - nulledCastedField = queries[Backend.getIdentifiedDbms()].isnull.query % (nulledCastedField, nulledCastedField) + nulledCastedField = _.isnull.query % (nulledCastedField, nulledCastedField) else: - nulledCastedField = queries[Backend.getIdentifiedDbms()].isnull.query % nulledCastedField + nulledCastedField = _.isnull.query % nulledCastedField + + if conf.hexConvert: + if 'hex' in _: + nulledCastedField = _.hex.query % nulledCastedField + else: + warnMsg = "switch '--hex' is currently not supported on DBMS '%s'. " % Backend.getIdentifiedDbms() + warnMsg += "Going to switch it off" + singleTimeWarnMessage(warnMsg) + + conf.hexConvert = False return nulledCastedField diff --git a/lib/core/common.py b/lib/core/common.py index cb7f98c05..028796553 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1234,6 +1234,7 @@ def parseUnionPage(output, unique=True): for entry in output: entry = entry.group(1) + entry = decodeHexValue(entry) if conf.hexConvert else entry if unique: key = entry.lower() @@ -3098,35 +3099,63 @@ def getCounter(technique): return kb.counters.get(technique, 0) +def applyFunctionRecursively(value, function): + """ + Applies function recursively through list-like structures + """ + + if isinstance(value, (list, tuple, set, BigArray)): + retVal = [applyFunctionRecursively(_, function) for _ in value] + else: + retVal = function(value) + + return retVal + +def decodeHexValue(value): + """ + Returns value decoded from DBMS specific hexadecimal representation + """ + + def _(value): + if isinstance(value, basestring) and len(value) % 2 == 0: + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ORACLE, DBMS.PGSQL): + value = value.decode("hex") + elif Backend.isDbms(DBMS.MSSQL): + value = value[2:].decode("hex") + if value[1] == '\x00': + value = value.decode("utf16") + return value + + return applyFunctionRecursively(value, _) + def extractExpectedValue(value, expected): """ Extracts and returns expected value by a given type """ - if not expected: - return value + if expected: + value = unArrayizeValue(value) - value = unArrayizeValue(value) + if isNoneValue(value): + value = None + elif expected == EXPECTED.BOOL: + if isinstance(value, int): + value = bool(value) + elif isinstance(value, basestring): + value = value.strip().lower() + if value in ("true", "false"): + value = value == "true" + elif value in ("1", "-1"): + value = True + elif value == "0": + value = False + else: + value = None + elif expected == EXPECTED.INT: + if isinstance(value, basestring): + if value.isdigit(): + value = int(value) + else: + value = None - if isNoneValue(value): - value = None - elif expected == EXPECTED.BOOL: - if isinstance(value, int): - value = bool(value) - elif isinstance(value, basestring): - value = value.strip().lower() - if value in ("true", "false"): - value = value == "true" - elif value in ("1", "-1"): - value = True - elif value == "0": - value = False - else: - value = None - elif expected == EXPECTED.INT: - if isinstance(value, basestring): - if value.isdigit(): - value = int(value) - else: - value = None return value diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index bd0e602e8..f4fdbfd27 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -170,6 +170,7 @@ optDict = { "flushSession": "boolean", "forms": "boolean", "freshQueries": "boolean", + "hexConvert": "boolean", "parseErrors": "boolean", "replicate": "boolean", "updateAll": "boolean", diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 59f5d4287..6a35de77c 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -522,6 +522,10 @@ def cmdLineParser(): action="store_true", help="Ignores query results stored in session file") + general.add_option("--hex", dest="hexConvert", + action="store_true", + help="Uses DBMS hex conversion function(s) for data retrieval") + general.add_option("--parse-errors", dest="parseErrors", action="store_true", help="Parse and display DBMS error messages from responses") diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 0ed91a94e..038ad4105 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -14,6 +14,7 @@ import traceback from lib.core.agent import agent from lib.core.common import Backend from lib.core.common import dataToStdout +from lib.core.common import decodeHexValue from lib.core.common import decodeIntToUnicode from lib.core.common import filterControlChars from lib.core.common import getCharset @@ -520,6 +521,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None logger.info(infoMsg) if finalValue is not None: + finalValue = decodeHexValue(finalValue) if conf.hexConvert else finalValue conf.hashDB.write(expression, finalValue) else: conf.hashDB.write(expression, "%s%s" % (PARTIAL_VALUE_MARKER, partialValue)) diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index ee32aa435..a3e6eefa0 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -16,6 +16,7 @@ from lib.core.bigarray import BigArray from lib.core.common import Backend from lib.core.common import calculateDeltaSeconds from lib.core.common import dataToStdout +from lib.core.common import decodeHexValue from lib.core.common import extractRegexResult from lib.core.common import getUnicode from lib.core.common import incrementCounter @@ -123,6 +124,8 @@ def __oneShotErrorUse(expression, field): retVal = output break + retVal = decodeHexValue(retVal) if conf.hexConvert else retVal + if isinstance(retVal, basestring): retVal = htmlunescape(retVal).replace("
", "\n") diff --git a/sqlmap.conf b/sqlmap.conf index 5430f08d4..85445d9ed 100644 --- a/sqlmap.conf +++ b/sqlmap.conf @@ -102,7 +102,7 @@ proxy = # Syntax: username:password pCred = -# Ignore system default HTTP proxy +# Ignore system default HTTP proxy. # Valid: True or False ignoreProxy = False @@ -121,21 +121,21 @@ timeout = 30 # Default: 3 retries = 3 -# Regular expression for filtering targets from provided Burp +# Regular expression for filtering targets from provided Burp. # or WebScarab proxy log. # Example: (google|yahoo) scope = -# Url address to visit frequently during testing +# Url address to visit frequently during testing. # Example: http://192.168.1.121/index.html safUrl = -# Test requests between two visits to a given safe url (default 0) +# Test requests between two visits to a given safe url (default 0). # Valid: integer # Default: 0 saFreq = 0 -# Evaluate provided Python code before the request +# Evaluate provided Python code before the request. # Example: import hashlib;id2=hashlib.md5(id).hexdigest() evalCode = @@ -188,20 +188,20 @@ dbms = # Valid: linux, windows os = -# Injection payload prefix string +# Injection payload prefix string. prefix = -# Injection payload suffix string +# Injection payload suffix string. suffix = -# Use logic operation(s) instead of negating values +# Use logic operation(s) instead of negating values. # Valid: True or False logicNegative = False -# Skip testing for given parameter(s) +# Skip testing for given parameter(s). skip = -# Use given script(s) for tampering injection data +# Use given script(s) for tampering injection data. tamper = @@ -209,14 +209,14 @@ tamper = # content from HTTP responses when using blind SQL injection technique. [Detection] -# Level of tests to perform +# Level of tests to perform. # The higher the value is, the higher the number of HTTP(s) requests are # as well as the better chances to detect a tricky SQL injection. # Valid: Integer between 1 and 5 # Default: 1 level = 1 -# Risk of tests to perform +# Risk of tests to perform. # Note: boolean-based blind SQL injection tests with AND are considered # risk 1, with OR are considered risk 3. # Valid: Integer between 0 and 3 @@ -236,17 +236,17 @@ string = # (http://www.python.org/doc/2.5.2/lib/re-syntax.html) regexp = -# HTTP response code to match when the query is valid +# HTTP response code to match when the query is valid. # Valid: Integer # Example: 200 (assuming any False statement returns a different response # code) # code = -# Compare pages based only on the textual content +# Compare pages based only on the textual content. # Valid: True or False textOnly = False -# Compare pages based only on their titles +# Compare pages based only on their titles. # Valid: True or False titles = False @@ -497,28 +497,28 @@ tmpPath = # system Windows registry. [Windows] -# Read a Windows registry key value +# Read a Windows registry key value. # Valid: True or False regRead = False -# Write a Windows registry key value data +# Write a Windows registry key value data. # Valid: True or False regAdd = False -# Delete a Windows registry key value +# Delete a Windows registry key value. # Valid: True or False regDel = False -# Windows registry key +# Windows registry key. regKey = -# Windows registry key value +# Windows registry key value. regVal = -# Windows registry key value data +# Windows registry key value data. regData = -# Windows registry key value type +# Windows registry key value type. regType = @@ -538,11 +538,11 @@ batch = False # Force character encoding used for data retrieval. charset = -# Check to see if Tor is used properly +# Check to see if Tor is used properly. # Valid: True or False checkTor = False -# Crawl the website starting from the target url +# Crawl the website starting from the target url. # Valid: integer # Default: 0 crawlDepth = 0 @@ -560,7 +560,7 @@ eta = False # Valid: True or False flushSession = False -# Parse and test forms on target url +# Parse and test forms on target url. # Valid: True or False forms = False @@ -568,6 +568,10 @@ forms = False # Valid: True or False freshQueries = False +# Uses DBMS hex conversion function(s) for data retrieval. +# Valid: True or False +hexConvert = False + # Parse and display DBMS error messages from responses. # Valid: True or False parseErrors = False @@ -580,7 +584,7 @@ replicate = False # Valid: True or False tor = False -# Set Tor proxy port other than default +# Set Tor proxy port other than default. # Valid: integer # torPort =