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 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,

View File

@ -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)"},
}

View File

@ -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))

View File

@ -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)

View File

@ -274,7 +274,7 @@
</columns>
<dump_table>
<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>
<!-- NOTE: in Oracle schema names are the counterpart to database names on other DBMSes -->
<search_db>
@ -608,7 +608,7 @@
</columns>
<dump_table>
<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>
<search_db>
<inband query="SELECT schemaname FROM syscat.schemata WHERE " condition="schemaname"/>