diff --git a/lib/core/agent.py b/lib/core/agent.py index 6b56b8ef0..edc6530ab 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -15,10 +15,12 @@ from lib.core.common import isNumber from lib.core.common import isTechniqueAvailable from lib.core.common import randomInt from lib.core.common import randomStr +from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import singleTimeWarnMessage from lib.core.data import conf from lib.core.data import kb from lib.core.data import queries +from lib.core.dicts import DUMP_DATA_PREPROCESS from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import DBMS from lib.core.enums import PAYLOAD @@ -463,6 +465,25 @@ class Agent(object): rootQuery = queries[Backend.getIdentifiedDbms()] return rootQuery.concatenate.query % (first, second) + def preprocessField(self, table, field): + """ + Does a field preprocessing (if needed) based on it's type (e.g. image to text) + Note: used primarily in dumping of custom tables + """ + + retVal = field + if conf.db in table: + table = table.split(conf.db)[-1].strip('.') + try: + columns = kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(table, True)] + for name, type_ in columns.items(): + if type_ and type_.upper() in DUMP_DATA_PREPROCESS.get(Backend.getDbms(), {}) and name == field: + retVal = DUMP_DATA_PREPROCESS[Backend.getDbms()][type_.upper()] % name + break + except KeyError: + pass + return retVal + def concatQuery(self, query, unpack=True): """ Take in input a query string and return its processed nulled, diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 926395d6a..acc2e338b 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -205,3 +205,8 @@ POST_HINT_CONTENT_TYPES = { DEPRECATED_HINTS = { "--replicate": "use '--dump-format=SQLITE' instead", } + +DUMP_DATA_PREPROCESS = { + DBMS.ORACLE: {"XMLTYPE": "(%s).getStringVal()"}, # Reference: https://www.tibcommunity.com/docs/DOC-3643 + DBMS.MSSQL: {"IMAGE": "CONVERT(VARBINARY(MAX),%s)"}, + } diff --git a/lib/utils/pivotdumptable.py b/lib/utils/pivotdumptable.py index a48f87903..b93b7c30d 100644 --- a/lib/utils/pivotdumptable.py +++ b/lib/utils/pivotdumptable.py @@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission """ from extra.safe2bin.safe2bin import safechardecode +from lib.core.agent import agent from lib.core.bigarray import BigArray from lib.core.common import Backend from lib.core.common import isNoneValue @@ -101,9 +102,9 @@ def pivotDumpTable(table, colList, count=None, blind=True): for column in colList: def _(pivotValue): if column == colList[0]: - query = dumpNode.query.replace("'%s'", "%s") % (column, table, column, unescaper.unescape(pivotValue, False)) + query = dumpNode.query.replace("'%s'", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, column), unescaper.unescape(pivotValue, False)) else: - query = dumpNode.query2.replace("'%s'", "%s") % (column, table, colList[0], unescaper.unescape(pivotValue, False)) + query = dumpNode.query2.replace("'%s'", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, colList[0]), unescaper.unescape(pivotValue, False)) return unArrayizeValue(inject.getValue(query, blind=blind, time=blind, union=not blind, error=not blind)) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 5586b6d51..659f9cdda 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -5,6 +5,9 @@ Copyright (c) 2006-2012 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ +import re + +from lib.core.agent import agent from lib.core.bigarray import BigArray from lib.core.common import Backend from lib.core.common import clearConsoleLine @@ -117,17 +120,23 @@ class Entries: continue - colList = sorted(filter(None, kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)].keys())) - colString = ", ".join(column for column in colList) + columns = kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] + colList = sorted(filter(None, columns.keys())) + colNames = colString = ", ".join(column for column in colList) rootQuery = queries[Backend.getIdentifiedDbms()].dump_table infoMsg = "fetching entries" if conf.col: - infoMsg += " of column(s) '%s'" % colString + infoMsg += " of column(s) '%s'" % colNames infoMsg += " for table '%s'" % unsafeSQLIdentificatorNaming(tbl) infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) + for column in colList: + _ = agent.preprocessField(tbl, column) + if _ != column: + colString = re.sub(r"\b%s\b" % column, _, colString) + entriesCount = 0 if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: @@ -190,7 +199,7 @@ class Entries: if not kb.data.dumpedTable and isInferenceAvailable() and not conf.direct: infoMsg = "fetching number of " if conf.col: - infoMsg += "column(s) '%s' " % colString + infoMsg += "column(s) '%s' " % colNames infoMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) @@ -224,7 +233,7 @@ class Entries: elif not isNumPosStrValue(count): warnMsg = "unable to retrieve the number of " if conf.col: - warnMsg += "column(s) '%s' " % colString + warnMsg += "column(s) '%s' " % colNames warnMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.warn(warnMsg) @@ -269,16 +278,16 @@ class Entries: entries[column] = BigArray() if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): - query = rootQuery.blind.query % (column, conf.db, conf.tbl, sorted(colList, key=len)[0], index) + query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): - query = rootQuery.blind.query % (column, column, + query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) elif Backend.isDbms(DBMS.SQLITE): - query = rootQuery.blind.query % (column, tbl, index) + query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl, index) elif Backend.isDbms(DBMS.FIREBIRD): - query = rootQuery.blind.query % (index, column, tbl) + query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), tbl) value = NULL if column in emptyColumns else inject.getValue(query, union=False, error=False, dump=True) value = '' if value is None else value @@ -302,7 +311,7 @@ class Entries: if len(kb.data.dumpedTable) == 0 or (entriesCount == 0 and kb.permissionFlag): warnMsg = "unable to retrieve the entries " if conf.col: - warnMsg += "of columns '%s' " % colString + warnMsg += "of columns '%s' " % colNames warnMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'%s" % (unsafeSQLIdentificatorNaming(conf.db), " (permission denied)" if kb.permissionFlag else "") logger.warn(warnMsg) diff --git a/xml/queries.xml b/xml/queries.xml index 917a865d2..c40c76798 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -274,7 +274,7 @@ - + @@ -608,7 +608,7 @@ - +