diff --git a/lib/core/agent.py b/lib/core/agent.py index 68fc22817..1604f83cd 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -37,6 +37,7 @@ from lib.core.settings import BOUNDARY_BACKSLASH_MARKER from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR from lib.core.settings import DEFAULT_COOKIE_DELIMITER from lib.core.settings import DEFAULT_GET_POST_DELIMITER +from lib.core.settings import DEFAULT_MYSQL_CHARACTER_SET from lib.core.settings import GENERIC_SQL_COMMENT from lib.core.settings import PAYLOAD_DELIMITER from lib.core.settings import REPLACEMENT_MARKER @@ -400,7 +401,10 @@ class Agent(object): nulledCastedField = field else: if not (Backend.isDbms(DBMS.SQLITE) and not isDBMSVersionAtLeast('3')): - nulledCastedField = rootQuery.cast.query % field + if Backend.isDbms(DBMS.MYSQL): + nulledCastedField = rootQuery.cast.query.replace(")", " CHARACTER SET %s)") % (field, DEFAULT_MYSQL_CHARACTER_SET) + else: + nulledCastedField = rootQuery.cast.query % field if Backend.getIdentifiedDbms() in (DBMS.ACCESS,): nulledCastedField = rootQuery.isnull.query % (nulledCastedField, nulledCastedField) else: diff --git a/lib/core/settings.py b/lib/core/settings.py index d478ae50a..1e14fd755 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -224,6 +224,10 @@ HOST_ALIASES = ("host",) HSQLDB_DEFAULT_SCHEMA = "PUBLIC" +# Default character set used in MySQL +# Reference: http://pieroxy.net/blog/2013/05/28/mysql_charset_hell.html +DEFAULT_MYSQL_CHARACTER_SET = "latin1" + # Names that can't be used to name files on Windows OS WINDOWS_RESERVED_NAMES = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9") diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 11e78ed6c..39fad7e77 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -8,6 +8,7 @@ See the file 'doc/COPYING' for copying permission import threading import time +from extra.safe2bin.safe2bin import safechardecode from extra.safe2bin.safe2bin import safecharencode from lib.core.agent import agent from lib.core.common import Backend @@ -18,6 +19,7 @@ from lib.core.common import decodeIntToUnicode from lib.core.common import filterControlChars from lib.core.common import getCharset from lib.core.common import getCounter +from lib.core.common import getUnicode from lib.core.common import goGoodSamaritan from lib.core.common import getPartRun from lib.core.common import hashDBRetrieve @@ -35,6 +37,7 @@ from lib.core.enums import DBMS from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapThreadException from lib.core.settings import CHAR_INFERENCE_MARK +from lib.core.settings import DEFAULT_MYSQL_CHARACTER_SET from lib.core.settings import INFERENCE_BLANK_BREAK from lib.core.settings import INFERENCE_UNKNOWN_CHAR from lib.core.settings import INFERENCE_GREATER_CHAR @@ -589,6 +592,10 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None raise KeyboardInterrupt _ = finalValue or partialValue + + if Backend.isDbms(DBMS.MYSQL) and safechardecode(_) != _: + _ = getUnicode(safechardecode(_).encode(DEFAULT_MYSQL_CHARACTER_SET)) + return getCounter(kb.technique), safecharencode(_) if kb.safeCharEncode else _ def queryOutputLength(expression, payload): diff --git a/plugins/dbms/mysql/syntax.py b/plugins/dbms/mysql/syntax.py index e593a51fb..312141b55 100644 --- a/plugins/dbms/mysql/syntax.py +++ b/plugins/dbms/mysql/syntax.py @@ -8,6 +8,7 @@ See the file 'doc/COPYING' for copying permission import binascii from lib.core.convert import utf8encode +from lib.core.settings import DEFAULT_MYSQL_CHARACTER_SET from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): @@ -26,7 +27,7 @@ class Syntax(GenericSyntax): try: retVal = "0x%s" % binascii.hexlify(value) except UnicodeEncodeError: - retVal = "CONVERT(0x%s USING utf8)" % "".join("%.2x" % ord(_) for _ in utf8encode(value)) + retVal = "CONVERT(0x%s USING %s)" % ("".join("%.2x" % ord(_) for _ in utf8encode(value)), DEFAULT_MYSQL_CHARACTER_SET) return retVal return Syntax._escape(expression, quote, escaper) diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index 23826f7e7..4332ea4c4 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -31,6 +31,7 @@ class Enumeration(Custom, Databases, Entries, Search, Users): kb.data.banner = None kb.data.hostname = "" kb.data.processChar = None + kb.data.characterSet = None Custom.__init__(self) Databases.__init__(self) diff --git a/xml/queries.xml b/xml/queries.xml index 28fd85bfb..98b79cac7 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -3,7 +3,7 @@ - +