diff --git a/plugins/dbms/maxdb/enumeration.py b/plugins/dbms/maxdb/enumeration.py index e77cc69dd..9f3e3330f 100644 --- a/plugins/dbms/maxdb/enumeration.py +++ b/plugins/dbms/maxdb/enumeration.py @@ -16,6 +16,7 @@ from lib.core.data import queries from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapNoneDataException from lib.core.settings import CURRENT_DB +from lib.utils.pivotdumptable import pivotDumpTable from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): @@ -40,7 +41,7 @@ class Enumeration(GenericEnumeration): rootQuery = queries[Backend.getIdentifiedDbms()].dbs randStr = randomStr() query = rootQuery.inband.query - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.schemaname' % randStr], blind=True) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.schemaname' % randStr], blind=True) if retVal: kb.data.cachedDbs = retVal[0].values()[0] @@ -76,7 +77,7 @@ class Enumeration(GenericEnumeration): for db in dbs: randStr = randomStr() query = rootQuery.inband.query % (("'%s'" % db) if db != "USER" else 'USER') - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.tablename' % randStr], blind=True) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.tablename' % randStr], blind=True) if retVal: for table in retVal[0].values()[0]: @@ -147,7 +148,7 @@ class Enumeration(GenericEnumeration): randStr = randomStr() query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), ("'%s'" % unsafeSQLIdentificatorNaming(conf.db)) if unsafeSQLIdentificatorNaming(conf.db) != "USER" else 'USER') - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.columnname' % randStr,'%s.datatype' % randStr,'%s.len' % randStr], blind=True) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.columnname' % randStr,'%s.datatype' % randStr,'%s.len' % randStr], blind=True) if retVal: table = {} diff --git a/plugins/dbms/sybase/enumeration.py b/plugins/dbms/sybase/enumeration.py index 101aa0bc4..1f67a8d8a 100644 --- a/plugins/dbms/sybase/enumeration.py +++ b/plugins/dbms/sybase/enumeration.py @@ -20,6 +20,7 @@ from lib.core.enums import PAYLOAD from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapNoneDataException from lib.core.settings import CURRENT_DB +from lib.utils.pivotdumptable import pivotDumpTable from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): @@ -41,7 +42,7 @@ class Enumeration(GenericEnumeration): blinds = (True,) for blind in blinds: - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind) if retVal: kb.data.cachedUsers = retVal[0].values()[0] @@ -95,7 +96,7 @@ class Enumeration(GenericEnumeration): blinds = [True] for blind in blinds: - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind) if retVal: kb.data.cachedDbs = retVal[0].values()[0] @@ -140,7 +141,7 @@ class Enumeration(GenericEnumeration): for blind in blinds: randStr = randomStr() query = rootQuery.inband.query % db - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind) if retVal: for table in retVal[0].values()[0]: @@ -232,7 +233,7 @@ class Enumeration(GenericEnumeration): for blind in blinds: randStr = randomStr() query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl)) - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr,'%s.usertype' % randStr], blind=blind) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr,'%s.usertype' % randStr], blind=blind) if retVal: table = {} diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index a5328c974..660fc87e5 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -42,6 +42,7 @@ from lib.core.settings import MAX_INT from lib.core.settings import NULL from lib.request import inject from lib.utils.hash import attackDumpedTable +from lib.utils.pivotdumptable import pivotDumpTable class Entries: """ @@ -51,129 +52,6 @@ class Entries: def __init__(self): pass - def __pivotDumpTable(self, table, colList, count=None, blind=True): - lengths = {} - entries = {} - - dumpNode = queries[Backend.getIdentifiedDbms()].dump_table.blind - - validColumnList = False - validPivotValue = False - - if count is None: - query = dumpNode.count % table - count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if blind else inject.getValue(query, blind=False, expected=EXPECTED.INT) - - if isinstance(count, basestring) and count.isdigit(): - count = int(count) - - if count == 0: - infoMsg = "table '%s' appears to be empty" % unsafeSQLIdentificatorNaming(table) - logger.info(infoMsg) - - for column in colList: - lengths[column] = len(column) - entries[column] = [] - - return entries, lengths - - elif not isNumPosStrValue(count): - return None - - for column in colList: - lengths[column] = 0 - entries[column] = BigArray() - - colList = filter(None, sorted(colList, key=lambda x: len(x) if x else MAX_INT)) - - for column in colList: - infoMsg = "fetching number of distinct " - infoMsg += "values for column '%s'" % column - logger.info(infoMsg) - - query = dumpNode.count2 % (column, table) - value = inject.getValue(query, blind=blind, inband=not blind, error=not blind, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) - - if isNumPosStrValue(value): - validColumnList = True - - if value == count: - infoMsg = "using column '%s' as a pivot " % column - infoMsg += "for retrieving row data" - logger.info(infoMsg) - - validPivotValue = True - - colList.remove(column) - colList.insert(0, column) - break - - if not validColumnList: - errMsg = "all column name(s) provided are non-existent" - raise sqlmapNoneDataException, errMsg - - if not validPivotValue: - warnMsg = "no proper pivot column provided (with unique values)." - warnMsg += " It won't be possible to retrieve all rows" - logger.warn(warnMsg) - - pivotValue = " " - breakRetrieval = False - - try: - for i in xrange(count): - if breakRetrieval: - break - - for column in colList: - # Correction for pivotValues with unrecognized/problematic chars - for char in ('\'', '?'): - if pivotValue and char in pivotValue and pivotValue[0] != char: - pivotValue = pivotValue.split(char)[0] - pivotValue = pivotValue[:-1] + decodeIntToUnicode(ord(pivotValue[-1]) + 1) - break - if column == colList[0]: - query = dumpNode.query % (column, table, column, pivotValue) - else: - query = dumpNode.query2 % (column, table, colList[0], pivotValue) - - value = inject.getValue(query, blind=blind, inband=not blind, error=not blind) - - if column == colList[0]: - if isNoneValue(value): - breakRetrieval = True - break - else: - pivotValue = safechardecode(value) - - if conf.limitStart or conf.limitStop: - if conf.limitStart and (i + 1) < conf.limitStart: - warnMsg = "skipping first %d pivot " % conf.limitStart - warnMsg += "point values" - singleTimeWarnMessage(warnMsg) - break - elif conf.limitStop and (i + 1) > conf.limitStop: - breakRetrieval = True - break - - value = "" if isNoneValue(value) else unArrayizeValue(value) - - lengths[column] = max(lengths[column], len(value) if value else 0) - entries[column].append(value) - - except KeyboardInterrupt: - warnMsg = "user aborted during enumeration. sqlmap " - warnMsg += "will display partial output" - logger.warn(warnMsg) - - except sqlmapConnectionException, e: - errMsg = "connection exception detected. sqlmap " - errMsg += "will display partial output" - errMsg += "'%s'" % e - logger.critical(errMsg) - - return entries, lengths - def dumpTable(self, foundData=None): self.forceDbmsEnum() @@ -269,7 +147,7 @@ class Entries: if not (isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL): table = "%s.%s" % (conf.db, tbl) - retVal = self.__pivotDumpTable(table, colList, blind=False) + retVal = pivotDumpTable(table, colList, blind=False) if retVal: entries, _ = retVal @@ -365,7 +243,7 @@ class Entries: elif Backend.isDbms(DBMS.MAXDB): table = "%s.%s" % (conf.db, tbl) - retVal = self.__pivotDumpTable(table, colList, count, blind=True) + retVal = pivotDumpTable(table, colList, count, blind=True) if retVal: entries, lengths = retVal diff --git a/plugins/generic/users.py b/plugins/generic/users.py index 8ffbefc4a..429222740 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -39,6 +39,7 @@ from lib.core.exception import sqlmapUserQuitException from lib.core.threads import getCurrentThreadData from lib.request import inject from lib.utils.hash import attackCachedUsersPasswords +from lib.utils.pivotdumptable import pivotDumpTable class Users: """ @@ -179,7 +180,7 @@ class Users: randStr = randomStr() getCurrentThreadData().disableStdOut = True - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr, '%s.password' % randStr], blind=False) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr, '%s.password' % randStr], blind=False) if retVal: for user, password in filterPairValues(zip(retVal[0]["%s.name" % randStr], retVal[0]["%s.password" % randStr])): @@ -221,7 +222,7 @@ class Users: randStr = randomStr() query = rootQuery.inband.query - retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr, '%s.password' % randStr], blind=True) + retVal = pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr, '%s.password' % randStr], blind=True) if retVal: for user, password in filterPairValues(zip(retVal[0]["%s.name" % randStr], retVal[0]["%s.password" % randStr])):