Implementation for an Issue #340

This commit is contained in:
Miroslav Stampar 2013-01-15 16:05:33 +01:00
parent 3f84cefc77
commit 7a1d484115
5 changed files with 50 additions and 14 deletions

View File

@ -15,10 +15,12 @@ from lib.core.common import isNumber
from lib.core.common import isTechniqueAvailable from lib.core.common import isTechniqueAvailable
from lib.core.common import randomInt from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import safeSQLIdentificatorNaming
from lib.core.common import singleTimeWarnMessage from lib.core.common import singleTimeWarnMessage
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import queries 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.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS from lib.core.enums import DBMS
from lib.core.enums import PAYLOAD from lib.core.enums import PAYLOAD
@ -463,6 +465,25 @@ class Agent(object):
rootQuery = queries[Backend.getIdentifiedDbms()] rootQuery = queries[Backend.getIdentifiedDbms()]
return rootQuery.concatenate.query % (first, second) 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): def concatQuery(self, query, unpack=True):
""" """
Take in input a query string and return its processed nulled, Take in input a query string and return its processed nulled,

View File

@ -205,3 +205,8 @@ POST_HINT_CONTENT_TYPES = {
DEPRECATED_HINTS = { DEPRECATED_HINTS = {
"--replicate": "use '--dump-format=SQLITE' instead", "--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)"},
}

View File

@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission
""" """
from extra.safe2bin.safe2bin import safechardecode from extra.safe2bin.safe2bin import safechardecode
from lib.core.agent import agent
from lib.core.bigarray import BigArray from lib.core.bigarray import BigArray
from lib.core.common import Backend from lib.core.common import Backend
from lib.core.common import isNoneValue from lib.core.common import isNoneValue
@ -101,9 +102,9 @@ def pivotDumpTable(table, colList, count=None, blind=True):
for column in colList: for column in colList:
def _(pivotValue): def _(pivotValue):
if column == colList[0]: 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: 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)) return unArrayizeValue(inject.getValue(query, blind=blind, time=blind, union=not blind, error=not blind))

View File

@ -5,6 +5,9 @@ Copyright (c) 2006-2012 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission 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.bigarray import BigArray
from lib.core.common import Backend from lib.core.common import Backend
from lib.core.common import clearConsoleLine from lib.core.common import clearConsoleLine
@ -117,17 +120,23 @@ class Entries:
continue continue
colList = sorted(filter(None, kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)].keys())) columns = kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)]
colString = ", ".join(column for column in colList) colList = sorted(filter(None, columns.keys()))
colNames = colString = ", ".join(column for column in colList)
rootQuery = queries[Backend.getIdentifiedDbms()].dump_table rootQuery = queries[Backend.getIdentifiedDbms()].dump_table
infoMsg = "fetching entries" infoMsg = "fetching entries"
if conf.col: if conf.col:
infoMsg += " of column(s) '%s'" % colString infoMsg += " of column(s) '%s'" % colNames
infoMsg += " for table '%s'" % unsafeSQLIdentificatorNaming(tbl) infoMsg += " for table '%s'" % unsafeSQLIdentificatorNaming(tbl)
infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
logger.info(infoMsg) logger.info(infoMsg)
for column in colList:
_ = agent.preprocessField(tbl, column)
if _ != column:
colString = re.sub(r"\b%s\b" % column, _, colString)
entriesCount = 0 entriesCount = 0
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: 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: if not kb.data.dumpedTable and isInferenceAvailable() and not conf.direct:
infoMsg = "fetching number of " infoMsg = "fetching number of "
if conf.col: if conf.col:
infoMsg += "column(s) '%s' " % colString infoMsg += "column(s) '%s' " % colNames
infoMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl)
infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
logger.info(infoMsg) logger.info(infoMsg)
@ -224,7 +233,7 @@ class Entries:
elif not isNumPosStrValue(count): elif not isNumPosStrValue(count):
warnMsg = "unable to retrieve the number of " warnMsg = "unable to retrieve the number of "
if conf.col: if conf.col:
warnMsg += "column(s) '%s' " % colString warnMsg += "column(s) '%s' " % colNames
warnMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "entries for table '%s' " % unsafeSQLIdentificatorNaming(tbl)
warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
logger.warn(warnMsg) logger.warn(warnMsg)
@ -269,16 +278,16 @@ class Entries:
entries[column] = BigArray() entries[column] = BigArray()
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): 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): 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())), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())),
index) index)
elif Backend.isDbms(DBMS.SQLITE): 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): 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 = NULL if column in emptyColumns else inject.getValue(query, union=False, error=False, dump=True)
value = '' if value is None else value 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): if len(kb.data.dumpedTable) == 0 or (entriesCount == 0 and kb.permissionFlag):
warnMsg = "unable to retrieve the entries " warnMsg = "unable to retrieve the entries "
if conf.col: if conf.col:
warnMsg += "of columns '%s' " % colString warnMsg += "of columns '%s' " % colNames
warnMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl)
warnMsg += "in database '%s'%s" % (unsafeSQLIdentificatorNaming(conf.db), " (permission denied)" if kb.permissionFlag else "") warnMsg += "in database '%s'%s" % (unsafeSQLIdentificatorNaming(conf.db), " (permission denied)" if kb.permissionFlag else "")
logger.warn(warnMsg) logger.warn(warnMsg)

View File

@ -274,7 +274,7 @@
</columns> </columns>
<dump_table> <dump_table>
<inband query="SELECT %s FROM %s"/> <inband query="SELECT %s FROM %s"/>
<blind query="SELECT %s FROM (SELECT %s,ROWNUM AS LIMIT FROM %s) WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/> <blind query="SELECT ENTRY_VALUE FROM (SELECT %s AS ENTRY_VALUE,ROWNUM AS LIMIT FROM %s) WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/>
</dump_table> </dump_table>
<!-- NOTE: in Oracle schema names are the counterpart to database names on other DBMSes --> <!-- NOTE: in Oracle schema names are the counterpart to database names on other DBMSes -->
<search_db> <search_db>
@ -608,7 +608,7 @@
</columns> </columns>
<dump_table> <dump_table>
<inband query="SELECT %s FROM %s"/> <inband query="SELECT %s FROM %s"/>
<blind query="SELECT %s FROM (SELECT ROW_NUMBER() OVER () AS LIMIT,%s FROM %s) AS foobar WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/> <blind query="SELECT ENTRY_VALUE FROM (SELECT ROW_NUMBER() OVER () AS LIMIT,%s AS ENTRY_VALUE FROM %s) AS foobar WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/>
</dump_table> </dump_table>
<search_db> <search_db>
<inband query="SELECT schemaname FROM syscat.schemata WHERE " condition="schemaname"/> <inband query="SELECT schemaname FROM syscat.schemata WHERE " condition="schemaname"/>