mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-07-10 10:33:09 +00:00
Merge branch 'master' into hana-pr
# Conflicts: # data/txt/sha256sums.txt # lib/core/common.py # lib/core/settings.py
This commit is contained in:
commit
1465d55a47
239 changed files with 57035 additions and 4345 deletions
|
|
@ -70,6 +70,7 @@ class Databases(object):
|
|||
kb.data.cachedCounts = {}
|
||||
kb.data.dumpedTable = {}
|
||||
kb.data.cachedStatements = []
|
||||
kb.data.cachedProcedures = []
|
||||
|
||||
def getCurrentDb(self):
|
||||
infoMsg = "fetching current database"
|
||||
|
|
@ -304,7 +305,7 @@ class Databases(object):
|
|||
if conf.excludeSysDbs:
|
||||
infoMsg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in self.excludeDbsList))
|
||||
logger.info(infoMsg)
|
||||
query += " IN (%s)" % ','.join("'%s'" % unsafeSQLIdentificatorNaming(db) for db in sorted(dbs) if db not in self.excludeDbsList)
|
||||
query += " IN (%s)" % ','.join("'%s'" % unsafeSQLIdentificatorNaming(db) for db in sorted(dbs) if unsafeSQLIdentificatorNaming(db) not in self.excludeDbsList)
|
||||
else:
|
||||
query += " IN (%s)" % ','.join("'%s'" % unsafeSQLIdentificatorNaming(db) for db in sorted(dbs))
|
||||
|
||||
|
|
@ -356,7 +357,7 @@ class Databases(object):
|
|||
|
||||
if not kb.data.cachedTables and isInferenceAvailable() and not conf.direct:
|
||||
for db in dbs:
|
||||
if conf.excludeSysDbs and db in self.excludeDbsList:
|
||||
if conf.excludeSysDbs and unsafeSQLIdentificatorNaming(db) in self.excludeDbsList:
|
||||
infoMsg = "skipping system database '%s'" % unsafeSQLIdentificatorNaming(db)
|
||||
logger.info(infoMsg)
|
||||
continue
|
||||
|
|
@ -400,26 +401,40 @@ class Databases(object):
|
|||
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
|
||||
indexRange = getLimitRange(count, plusOne=plusOne)
|
||||
|
||||
for index in indexRange:
|
||||
if Backend.isDbms(DBMS.SYBASE):
|
||||
query = _query % (db, (kb.data.cachedTables[-1] if kb.data.cachedTables else " "))
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB):
|
||||
query = _query % (kb.data.cachedTables[-1] if kb.data.cachedTables else " ")
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD):
|
||||
query = _query % index
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.HSQLDB, DBMS.INFORMIX, DBMS.FRONTBASE, DBMS.VIRTUOSO):
|
||||
query = _query % (index, unsafeSQLIdentificatorNaming(db))
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.SPANNER,):
|
||||
query = _query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(db), index)
|
||||
else:
|
||||
query = _query % (unsafeSQLIdentificatorNaming(db), index)
|
||||
# Value-parallel, prediction-assisted name enumeration for the DBMSes using the
|
||||
# generic "<db>, <index>" blind template. Retrieves whole names concurrently (one per
|
||||
# worker, each decoded sequentially so wordlist prediction applies). Used with '--threads'
|
||||
# and under '--eta' (one whole-job bar/ETA) per valueParallelEligible(); plain single-thread
|
||||
# stays on the classic getValue loop, which still gets predictive inference via getPartRun.
|
||||
# The special templates stay serial.
|
||||
genericTemplate = Backend.getIdentifiedDbms() not in (DBMS.SYBASE, DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.SQLITE, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.INFORMIX, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.SPANNER)
|
||||
|
||||
table = unArrayizeValue(inject.getValue(query, union=False, error=False))
|
||||
if genericTemplate and inject.valueParallelEligible():
|
||||
for table in (inject._threadedInferenceValues(lambda index: _query % (unsafeSQLIdentificatorNaming(db), index), indexRange, context="Tables") or []):
|
||||
if not isNoneValue(table):
|
||||
kb.hintValue = table
|
||||
tables.append(safeSQLIdentificatorNaming(table, True))
|
||||
else:
|
||||
for index in indexRange:
|
||||
if Backend.isDbms(DBMS.SYBASE):
|
||||
query = _query % (db, (kb.data.cachedTables[-1] if kb.data.cachedTables else " "))
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB):
|
||||
query = _query % (kb.data.cachedTables[-1] if kb.data.cachedTables else " ")
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD):
|
||||
query = _query % index
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.HSQLDB, DBMS.INFORMIX, DBMS.FRONTBASE, DBMS.VIRTUOSO):
|
||||
query = _query % (index, unsafeSQLIdentificatorNaming(db))
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.SPANNER,):
|
||||
query = _query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(db), index)
|
||||
else:
|
||||
query = _query % (unsafeSQLIdentificatorNaming(db), index)
|
||||
|
||||
if not isNoneValue(table):
|
||||
kb.hintValue = table
|
||||
table = safeSQLIdentificatorNaming(table, True)
|
||||
tables.append(table)
|
||||
table = unArrayizeValue(inject.getValue(query, union=False, error=False))
|
||||
|
||||
if not isNoneValue(table):
|
||||
kb.hintValue = table
|
||||
table = safeSQLIdentificatorNaming(table, True)
|
||||
tables.append(table)
|
||||
|
||||
if tables:
|
||||
kb.data.cachedTables[db] = tables
|
||||
|
|
@ -840,7 +855,7 @@ class Databases(object):
|
|||
logger.error(errMsg)
|
||||
continue
|
||||
|
||||
for index in getLimitRange(count):
|
||||
def columnNameQuery(index):
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO):
|
||||
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
|
||||
query += condQuery
|
||||
|
|
@ -879,8 +894,24 @@ class Databases(object):
|
|||
query += condQuery
|
||||
field = condition
|
||||
|
||||
query = agent.limitQuery(index, query, field, field)
|
||||
column = unArrayizeValue(inject.getValue(query, union=False, error=False))
|
||||
return agent.limitQuery(index, query, field, field)
|
||||
|
||||
indexList = list(getLimitRange(count))
|
||||
|
||||
# Value-parallel column-NAME enumeration: the same axis/mechanism as getTables (one name per
|
||||
# worker, decoded sequentially - no length probe, predictive inference applies, names stream
|
||||
# live, and under '--eta' a single whole-job bar/ETA is drawn). Eligibility is shared via
|
||||
# valueParallelEligible(); serial fallback only when also fetching per-column comments (those
|
||||
# need an extra per-column query).
|
||||
columnNames = None
|
||||
if not conf.getComments and inject.valueParallelEligible():
|
||||
columnNames = inject._threadedInferenceValues(columnNameQuery, indexList, context="Columns")
|
||||
|
||||
for position, index in enumerate(indexList):
|
||||
if columnNames is not None:
|
||||
column = unArrayizeValue(columnNames[position])
|
||||
else:
|
||||
column = unArrayizeValue(inject.getValue(columnNameQuery(index), union=False, error=False))
|
||||
|
||||
if not isNoneValue(column):
|
||||
if conf.getComments:
|
||||
|
|
@ -1051,6 +1082,11 @@ class Databases(object):
|
|||
|
||||
rootQuery = queries[Backend.getIdentifiedDbms()].statements
|
||||
|
||||
if "inband" not in rootQuery and "blind" not in rootQuery:
|
||||
warnMsg = "on %s it is not possible to enumerate the SQL statements" % Backend.getIdentifiedDbms()
|
||||
logger.warning(warnMsg)
|
||||
return kb.data.cachedStatements
|
||||
|
||||
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
|
||||
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
|
||||
query = rootQuery.inband.query2
|
||||
|
|
@ -1122,3 +1158,62 @@ class Databases(object):
|
|||
kb.data.cachedStatements = [_.replace(REFLECTED_VALUE_MARKER, "<payload>") for _ in kb.data.cachedStatements]
|
||||
|
||||
return kb.data.cachedStatements
|
||||
|
||||
def getProcedures(self):
|
||||
infoMsg = "fetching stored procedures"
|
||||
logger.info(infoMsg)
|
||||
|
||||
rootQuery = queries[Backend.getIdentifiedDbms()].procedures
|
||||
|
||||
# Generic-first by design: a DBMS is supported iff it declares a <procedures> query block in
|
||||
# queries.xml (INFORMATION_SCHEMA.ROUTINES / pg_proc / sys.sql_modules / ALL_SOURCE / RDB$PROCEDURES).
|
||||
# Engines without stored procedures (or without a declared block) fall through with a clean
|
||||
# warning - same model as getStatements() (uneven coverage is the established convention).
|
||||
if "inband" not in rootQuery and "blind" not in rootQuery:
|
||||
warnMsg = "on %s it is not possible to enumerate the stored procedures" % Backend.getIdentifiedDbms()
|
||||
logger.warning(warnMsg)
|
||||
return kb.data.cachedProcedures
|
||||
|
||||
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
|
||||
query = rootQuery.inband.query
|
||||
|
||||
values = inject.getValue(query, blind=False, time=False)
|
||||
|
||||
if not isNoneValue(values):
|
||||
kb.data.cachedProcedures = []
|
||||
for value in arrayizeValue(values):
|
||||
value = (unArrayizeValue(value) or "").strip()
|
||||
if not isNoneValue(value):
|
||||
kb.data.cachedProcedures.append(value.strip())
|
||||
|
||||
if not kb.data.cachedProcedures and isInferenceAvailable() and not conf.direct:
|
||||
infoMsg = "fetching number of stored procedures"
|
||||
logger.info(infoMsg)
|
||||
|
||||
count = inject.getValue(rootQuery.blind.count, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
|
||||
|
||||
if count == 0:
|
||||
return kb.data.cachedProcedures
|
||||
elif not isNumPosStrValue(count):
|
||||
errMsg = "unable to retrieve the number of stored procedures"
|
||||
raise SqlmapNoneDataException(errMsg)
|
||||
|
||||
# every <procedures> blind query uses 0-based paging (MySQL "LIMIT %d,1", PostgreSQL/MSSQL/Oracle
|
||||
# "OFFSET %d"), so the index range stays 0-based here regardless of PLUS_ONE_DBMSES (unlike
|
||||
# getStatements(), whose MSSQL/Oracle idioms are 1-based)
|
||||
indexRange = getLimitRange(count)
|
||||
|
||||
for index in indexRange:
|
||||
query = rootQuery.blind.query % index
|
||||
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
|
||||
|
||||
if not isNoneValue(value):
|
||||
kb.data.cachedProcedures.append((value or "").strip())
|
||||
|
||||
if not kb.data.cachedProcedures:
|
||||
errMsg = "unable to retrieve the stored procedures"
|
||||
logger.error(errMsg)
|
||||
else:
|
||||
kb.data.cachedProcedures = [_.replace(REFLECTED_VALUE_MARKER, "<payload>") for _ in kb.data.cachedProcedures]
|
||||
|
||||
return kb.data.cachedProcedures
|
||||
|
|
|
|||
|
|
@ -42,12 +42,15 @@ from lib.core.exception import SqlmapNoneDataException
|
|||
from lib.core.exception import SqlmapUnsupportedFeatureException
|
||||
from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD
|
||||
from lib.core.settings import CURRENT_DB
|
||||
from lib.core.settings import KEYSET_MIN_ROWS
|
||||
from lib.core.settings import METADB_SUFFIX
|
||||
from lib.core.settings import NULL
|
||||
from lib.core.settings import PLUS_ONE_DBMSES
|
||||
from lib.core.settings import UPPER_CASE_DBMSES
|
||||
from lib.request import inject
|
||||
from lib.utils.hash import attackDumpedTable
|
||||
from lib.utils.keysetdump import keysetDumpTable
|
||||
from lib.utils.keysetdump import resolveKeysetCursor
|
||||
from lib.utils.pivotdumptable import pivotDumpTable
|
||||
from thirdparty import six
|
||||
from thirdparty.six.moves import zip as _zip
|
||||
|
|
@ -309,6 +312,9 @@ class Entries(object):
|
|||
|
||||
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
|
||||
|
||||
# keyset (seek) pagination: forced with --keyset, automatic for large tables, off with --no-keyset
|
||||
keysetCursor = resolveKeysetCursor(tbl, colList) if (not conf.noKeyset and isNumPosStrValue(count) and (conf.keyset or int(count) >= KEYSET_MIN_ROWS)) else None
|
||||
|
||||
lengths = {}
|
||||
entries = {}
|
||||
|
||||
|
|
@ -332,6 +338,19 @@ class Entries(object):
|
|||
|
||||
continue
|
||||
|
||||
elif keysetCursor:
|
||||
infoMsg = "using keyset (seek) pagination on column(s) '%s' " % ', '.join(keysetCursor)
|
||||
infoMsg += "for table '%s'" % unsafeSQLIdentificatorNaming(tbl)
|
||||
logger.info(infoMsg)
|
||||
|
||||
try:
|
||||
entries, lengths = keysetDumpTable(tbl, colList, count, keysetCursor)
|
||||
except KeyboardInterrupt:
|
||||
kb.dumpKeyboardInterrupt = True
|
||||
clearConsoleLine()
|
||||
warnMsg = "Ctrl+C detected in dumping phase"
|
||||
logger.warning(warnMsg)
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.SYBASE, DBMS.MAXDB, DBMS.MSSQL, DBMS.INFORMIX, DBMS.MCKOI, DBMS.RAIMA):
|
||||
if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.RAIMA):
|
||||
table = tbl
|
||||
|
|
@ -399,41 +418,74 @@ class Entries(object):
|
|||
debugMsg += "dumped as it appears to be empty"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
def cellQuery(column, index):
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE, DBMS.SPANNER):
|
||||
query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, prioritySortColumns(colList)[0], index)
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE,):
|
||||
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.getIdentifiedDbms() in (DBMS.MIMERSQL,):
|
||||
query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), prioritySortColumns(colList)[0], index)
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.EXTREMEDB):
|
||||
query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl, index)
|
||||
elif Backend.isDbms(DBMS.FIREBIRD):
|
||||
query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), tbl)
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO):
|
||||
query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl, prioritySortColumns(colList)[0])
|
||||
elif Backend.isDbms(DBMS.FRONTBASE):
|
||||
query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl)
|
||||
else:
|
||||
query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, tbl, index)
|
||||
|
||||
return agent.whereQuery(query)
|
||||
|
||||
try:
|
||||
for index in indexRange:
|
||||
# Value-parallel dumping: one whole cell per worker, decoded sequentially, so there
|
||||
# is NO per-cell LENGTH() probe (the position-parallel path needs one to split a
|
||||
# value's characters across threads) and the per-column Huffman model + low-cardinality
|
||||
# guessing engage under concurrency. Used for the boolean channel with '--threads', and
|
||||
# for the HTTP/2 timeless oracle (its per-thread connections make concurrency safe and
|
||||
# deterministic). Also used under '--eta' - including single-threaded time-based, the
|
||||
# slowest channel - to drive one whole-job progress bar/ETA (how long the dump takes)
|
||||
# instead of a per-cell counter. Eligibility (channel x threads/eta) is valueParallelEligible();
|
||||
# '--dns-domain' keeps the classic loop (its OOB fast path bypasses bisection).
|
||||
if not conf.dnsDomain and inject.valueParallelEligible():
|
||||
# One value-parallel pass over every (non-empty) cell, so there is a single
|
||||
# thread pool and values stream live as they complete - out of order, exactly
|
||||
# like the error/union dumps - instead of a silent progress counter.
|
||||
nonEmpty = [_ for _ in colList if _ not in emptyColumns]
|
||||
tasks = [(column, index) for column in nonEmpty for index in indexRange]
|
||||
retrieved = inject._threadedInferenceValues(lambda pair: cellQuery(pair[0], pair[1]), tasks, charsetType=None, dump=True) if tasks else []
|
||||
retrieved = retrieved if retrieved is not None else [None] * len(tasks)
|
||||
|
||||
offset = 0
|
||||
for column in colList:
|
||||
value = ""
|
||||
entries[column] = BigArray()
|
||||
lengths.setdefault(column, 0)
|
||||
|
||||
if column not in lengths:
|
||||
lengths[column] = 0
|
||||
|
||||
if column not in entries:
|
||||
entries[column] = BigArray()
|
||||
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE, DBMS.SPANNER):
|
||||
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, DBMS.DERBY, DBMS.ALTIBASE,):
|
||||
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.getIdentifiedDbms() in (DBMS.MIMERSQL,):
|
||||
query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), sorted(colList, key=len)[0], index)
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.EXTREMEDB):
|
||||
query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl, index)
|
||||
elif Backend.isDbms(DBMS.FIREBIRD):
|
||||
query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), tbl)
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO):
|
||||
query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl, sorted(colList, key=len)[0])
|
||||
elif Backend.isDbms(DBMS.FRONTBASE):
|
||||
query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl)
|
||||
if column in emptyColumns:
|
||||
values = [NULL] * len(indexRange)
|
||||
else:
|
||||
query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, tbl, index)
|
||||
values = retrieved[offset:offset + len(indexRange)]
|
||||
offset += len(indexRange)
|
||||
|
||||
query = agent.whereQuery(query)
|
||||
for value in values:
|
||||
value = '' if value is None else value
|
||||
lengths[column] = max(lengths[column], getConsoleLength(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value))))
|
||||
entries[column].append(value)
|
||||
else:
|
||||
for index in indexRange:
|
||||
for column in colList:
|
||||
if column not in lengths:
|
||||
lengths[column] = 0
|
||||
|
||||
value = NULL if column in emptyColumns else inject.getValue(query, union=False, error=False, dump=True)
|
||||
value = '' if value is None else value
|
||||
if column not in entries:
|
||||
entries[column] = BigArray()
|
||||
|
||||
lengths[column] = max(lengths[column], getConsoleLength(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value))))
|
||||
entries[column].append(value)
|
||||
value = NULL if column in emptyColumns else inject.getValue(cellQuery(column, index), union=False, error=False, dump=True)
|
||||
value = '' if value is None else value
|
||||
|
||||
lengths[column] = max(lengths[column], getConsoleLength(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value))))
|
||||
entries[column].append(value)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
kb.dumpKeyboardInterrupt = True
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ class Filesystem(object):
|
|||
logger.debug(debugMsg)
|
||||
|
||||
fileContent = self.stackedReadFile(remoteFile)
|
||||
elif Backend.isDbms(DBMS.MYSQL):
|
||||
elif Backend.isDbms(DBMS.MYSQL) or Backend.isDbms(DBMS.PGSQL):
|
||||
debugMsg = "going to try to read the file with non-stacked query "
|
||||
debugMsg += "SQL injection technique"
|
||||
logger.debug(debugMsg)
|
||||
|
|
|
|||
|
|
@ -26,18 +26,21 @@ class Syntax(object):
|
|||
retVal = expression
|
||||
|
||||
if quote:
|
||||
for item in re.findall(r"'[^']*'+", expression):
|
||||
original = item[1:-1]
|
||||
if original:
|
||||
# Match a full SQL string literal, honouring the '' (doubled single quote) escape - e.g.
|
||||
# 'a''b' is ONE literal whose value is a'b, not 'a'' followed by a dangling b'. The old
|
||||
# r"'[^']*'+" split on the inner '' and left the tail bare, corrupting the encoded payload.
|
||||
for item in re.findall(r"'(?:[^']|'')*'", expression):
|
||||
value = item[1:-1].replace("''", "'") # inner content with '' collapsed to the real quote
|
||||
if value:
|
||||
if Backend.isDbms(DBMS.SQLITE) and "X%s" % item in expression:
|
||||
continue
|
||||
if re.search(r"\[(SLEEPTIME|RAND)", original) is None: # e.g. '[SLEEPTIME]' marker
|
||||
replacement = escaper(original) if not conf.noEscape else original
|
||||
if re.search(r"\[(SLEEPTIME|RAND)", value) is None: # e.g. '[SLEEPTIME]' marker
|
||||
replacement = escaper(value) if not conf.noEscape else value
|
||||
|
||||
if replacement != original:
|
||||
if replacement != value:
|
||||
retVal = retVal.replace(item, replacement)
|
||||
elif len(original) != len(getBytes(original)) and "n'%s'" % original not in retVal and Backend.getDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.ORACLE, DBMS.MSSQL):
|
||||
retVal = retVal.replace("'%s'" % original, "n'%s'" % original)
|
||||
elif len(value) != len(getBytes(value)) and "n%s" % item not in retVal and Backend.getDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.ORACLE, DBMS.MSSQL):
|
||||
retVal = retVal.replace(item, "n%s" % item)
|
||||
else:
|
||||
retVal = escaper(expression)
|
||||
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ class Users(object):
|
|||
|
||||
# In MySQL >= 5.0 and Oracle we get the list
|
||||
# of privileges as string
|
||||
elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.SNOWFLAKE):
|
||||
elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID, DBMS.SNOWFLAKE, DBMS.CLICKHOUSE, DBMS.CRATEDB, DBMS.ALTIBASE):
|
||||
privileges.add(privilege)
|
||||
|
||||
# In MySQL < 5.0 we get Y if the privilege is
|
||||
|
|
@ -668,8 +668,8 @@ class Users(object):
|
|||
return (kb.data.cachedUsersPrivileges, areAdmins)
|
||||
|
||||
def getRoles(self, query2=False):
|
||||
warnMsg = "on %s the concept of roles does not " % Backend.getIdentifiedDbms()
|
||||
warnMsg += "exist. sqlmap will enumerate privileges instead"
|
||||
warnMsg = "enumeration of roles is not supported on %s; " % Backend.getIdentifiedDbms()
|
||||
warnMsg += "sqlmap will enumerate privileges instead"
|
||||
logger.warning(warnMsg)
|
||||
|
||||
return self.getPrivileges(query2)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue