From e0e2349529f766fec9bc7bbefbe8ff791b322d90 Mon Sep 17 00:00:00 2001 From: Bernardo Damele Date: Mon, 17 May 2010 16:16:49 +0000 Subject: [PATCH] Refactor to --search -C and minor bug fix - See #190. --- lib/core/dump.py | 2 +- plugins/dbms/mssqlserver/enumeration.py | 132 ++++++++- plugins/dbms/oracle/enumeration.py | 104 ++++++++ plugins/generic/enumeration.py | 339 ++++++++++-------------- xml/queries.xml | 10 +- 5 files changed, 373 insertions(+), 214 deletions(-) diff --git a/lib/core/dump.py b/lib/core/dump.py index fa7c7d0e4..1a9f16709 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -140,7 +140,7 @@ class Dump: for db, tblData in dbs.items(): for tbl, colData in tblData.items(): for col, dataType in colData.items(): - if column in col: + if column.lower() in col.lower(): if db in printDbs: if tbl in printDbs[db]: printDbs[db][tbl][col] = dataType diff --git a/plugins/dbms/mssqlserver/enumeration.py b/plugins/dbms/mssqlserver/enumeration.py index 31a2727ab..3033c1313 100644 --- a/plugins/dbms/mssqlserver/enumeration.py +++ b/plugins/dbms/mssqlserver/enumeration.py @@ -28,6 +28,7 @@ from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries +from lib.core.dump import dumper from lib.core.exception import sqlmapNoneDataException from lib.request import inject @@ -143,21 +144,19 @@ class Enumeration(GenericEnumeration): infoMsg += " '%s'" % tbl logger.info(infoMsg) - if conf.excludeSysDbs: - exclDbsQuery = "".join(" AND '%s' != %s" % (db, dbCond) for db in self.excludeDbsList) - infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList) - logger.info(infoMsg) - else: - exclDbsQuery = "" - tblQuery = "%s%s" % (tblCond, tblCondParam) tblQuery = tblQuery % tbl for db in foundTbls.keys(): + if conf.excludeSysDbs and db in self.excludeDbsList: + infoMsg = "skipping system database '%s'" % db + logger.info(infoMsg) + + continue + if kb.unionPosition or conf.direct: query = rootQuery["inband"]["query"] % db query += tblQuery - query += exclDbsQuery values = inject.getValue(query, blind=False) if values: @@ -204,3 +203,120 @@ class Enumeration(GenericEnumeration): foundTbls.pop(db) return foundTbls + + def searchColumn(self): + rootQuery = queries[kb.dbms].searchColumn + foundCols = {} + dbs = {} + colList = conf.col.split(",") + colCond = rootQuery["inband"]["condition"] + colConsider, colCondParam = self.likeOrExact("column") + + if not len(kb.data.cachedDbs): + enumDbs = self.getDbs() + else: + enumDbs = kb.data.cachedDbs + + for db in enumDbs: + dbs[db] = {} + + for column in colList: + infoMsg = "searching column" + if colConsider == "1": + infoMsg += "s like" + infoMsg += " '%s'" % column + logger.info(infoMsg) + + foundCols[column] = {} + + colQuery = "%s%s" % (colCond, colCondParam) + colQuery = colQuery % column + + for db in dbs.keys(): + if conf.excludeSysDbs and db in self.excludeDbsList: + infoMsg = "skipping system database '%s'" % db + logger.info(infoMsg) + + continue + + if kb.unionPosition or conf.direct: + query = rootQuery["inband"]["query"] % (db, db, db, db, db) + query += " AND %s" % colQuery.replace("[DB]", db) + values = inject.getValue(query, blind=False) + + if values: + if isinstance(values, str): + values = [ values ] + + for foundTbl in values: + if foundTbl not in dbs[db]: + dbs[db][foundTbl] = {} + + if colConsider == "1": + conf.db = db + conf.tbl = foundTbl + conf.col = column + + self.getColumns(onlyColNames=True) + + dbs[db][foundTbl].update(kb.data.cachedColumns[db][foundTbl]) + kb.data.cachedColumns = {} + else: + dbs[db][foundTbl][column] = None + + if db in foundCols[column]: + foundCols[column][db].append(foundTbl) + else: + foundCols[column][db] = [ foundTbl ] + else: + foundCols[column][db] = [] + + infoMsg = "fetching number of tables containing column" + if colConsider == "1": + infoMsg += "s like" + infoMsg += " '%s' in database '%s'" % (column, db) + logger.info(infoMsg) + + query = rootQuery["blind"]["count2"] + query = query % (db, db, db, db, db) + query += " AND %s" % colQuery.replace("[DB]", db) + count = inject.getValue(query, inband=False, expected="int", charsetType=2) + + if not count.isdigit() or not len(count) or count == "0": + warnMsg = "no tables contain column" + if colConsider == "1": + warnMsg += "s like" + warnMsg += " '%s' " % column + warnMsg += "in database '%s'" % db + logger.warn(warnMsg) + + continue + + indexRange = getRange(count) + + for index in indexRange: + query = rootQuery["blind"]["query2"] + query = query % (db, db, db, db, db) + query += " AND %s" % colQuery.replace("[DB]", db) + query = agent.limitQuery(index, query, colCond.replace("[DB]", db)) + tbl = inject.getValue(query, inband=False) + kb.hintValue = tbl + + if tbl not in dbs[db]: + dbs[db][tbl] = {} + + if colConsider == "1": + conf.db = db + conf.tbl = tbl + conf.col = column + + self.getColumns(onlyColNames=True) + + dbs[db][tbl].update(kb.data.cachedColumns[db][tbl]) + kb.data.cachedColumns = {} + else: + dbs[db][tbl][column] = None + + foundCols[column][db].append(tbl) + + self.dumpFoundColumn(dbs, foundCols, colConsider) diff --git a/plugins/dbms/oracle/enumeration.py b/plugins/dbms/oracle/enumeration.py index 2edd43578..64ca03bcc 100644 --- a/plugins/dbms/oracle/enumeration.py +++ b/plugins/dbms/oracle/enumeration.py @@ -22,6 +22,7 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ +from lib.core.agent import agent from lib.core.common import getRange from lib.core.data import conf from lib.core.data import kb @@ -186,3 +187,106 @@ class Enumeration(GenericEnumeration): logger.warn(warnMsg) return [] + + def searchColumn(self): + rootQuery = queries[kb.dbms].searchColumn + foundCols = {} + dbs = { "USERS": {} } + colList = conf.col.split(",") + colCond = rootQuery["inband"]["condition"] + colConsider, colCondParam = self.likeOrExact("column") + + for column in colList: + column = column.upper() + + infoMsg = "searching column" + if colConsider == "1": + infoMsg += "s like" + infoMsg += " '%s'" % column + logger.info(infoMsg) + + foundCols[column] = {} + + colQuery = "%s%s" % (colCond, colCondParam) + colQuery = colQuery % column + + for db in dbs.keys(): + if kb.unionPosition or conf.direct: + query = rootQuery["inband"]["query"] + query += colQuery + values = inject.getValue(query, blind=False) + + if values: + if isinstance(values, str): + values = [ values ] + + for foundTbl in values: + if foundTbl not in dbs[db]: + dbs[db][foundTbl] = {} + + if colConsider == "1": + conf.db = db + conf.tbl = foundTbl + conf.col = column + + self.getColumns(onlyColNames=True) + + dbs[db][foundTbl].update(kb.data.cachedColumns[db][foundTbl]) + kb.data.cachedColumns = {} + else: + dbs[db][foundTbl][column] = None + + if db in foundCols[column]: + foundCols[column][db].append(foundTbl) + else: + foundCols[column][db] = [ foundTbl ] + else: + foundCols[column][db] = [] + + infoMsg = "fetching number of tables containing column" + if colConsider == "1": + infoMsg += "s like" + infoMsg += " '%s' in database '%s'" % (column, db) + logger.info(infoMsg) + + query = rootQuery["blind"]["count2"] + query += " WHERE %s" % colQuery + count = inject.getValue(query, inband=False, expected="int", charsetType=2) + + if not count.isdigit() or not len(count) or count == "0": + warnMsg = "no tables contain column" + if colConsider == "1": + warnMsg += "s like" + warnMsg += " '%s' " % column + warnMsg += "in database '%s'" % db + logger.warn(warnMsg) + + continue + + indexRange = getRange(count) + + for index in indexRange: + query = rootQuery["blind"]["query2"] + query += " WHERE %s" % colQuery + query = agent.limitQuery(index, query) + tbl = inject.getValue(query, inband=False) + kb.hintValue = tbl + + if tbl not in dbs[db]: + dbs[db][tbl] = {} + + if colConsider == "1": + conf.db = db + conf.tbl = tbl + conf.col = column + + self.getColumns(onlyColNames=True) + + dbs[db][tbl].update(kb.data.cachedColumns[db][tbl]) + kb.data.cachedColumns = {} + else: + dbs[db][tbl][column] = None + + foundCols[column][db].append(tbl) + + self.dumpFoundColumn(dbs, foundCols, colConsider) diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index 5ddf6e206..5739e9845 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -1185,6 +1185,77 @@ class Enumeration: if data: dumper.dbTableValues(data) + def dumpFoundColumn(self, dbs, foundCols, colConsider): + if not dbs: + warnMsg = "no databases have tables containing any of the " + warnMsg += "provided columns" + logger.warn(warnMsg) + return + + dumper.dbColumns(foundCols, colConsider, dbs) + + message = "do you want to dump entries? [Y/n] " + output = readInput(message, default="Y") + + if output and output[0] not in ("y", "Y"): + return + + dumpFromDbs = [] + message = "which database(s)?\n[a]ll (default)\n" + + for db, tblData in dbs.items(): + if tblData: + message += "[%s]\n" % db + + message += "[q]uit" + test = readInput(message, default="a") + + if not test or test in ("a", "A"): + dumpFromDbs = dbs.keys() + elif test in ("q", "Q"): + return + else: + dumpFromDbs = test.replace(" ", "").split(",") + + for db, tblData in dbs.items(): + if db not in dumpFromDbs or not tblData: + continue + + conf.db = db + dumpFromTbls = [] + message = "which table(s) of database '%s'?\n" % db + message += "[a]ll (default)\n" + + for tbl in tblData: + message += "[%s]\n" % tbl + + message += "[s]kip\n" + message += "[q]uit" + test = readInput(message, default="a") + + if not test or test in ("a", "A"): + dumpFromTbls = tblData + elif test in ("s", "S"): + continue + elif test in ("q", "Q"): + return + else: + dumpFromTbls = test.replace(" ", "").split(",") + + for table, columns in tblData.items(): + if table not in dumpFromTbls: + continue + + conf.tbl = table + conf.col = ",".join(column for column in columns) + kb.data.cachedColumns = {} + kb.data.dumpedTable = {} + + data = self.dumpTable() + + if data: + dumper.dbTableValues(data) + def searchDb(self): foundDbs = [] rootQuery = queries[kb.dbms].searchDb @@ -1405,10 +1476,6 @@ class Enumeration: colConsider, colCondParam = self.likeOrExact("column") for column in colList: - if kb.dbms == "Oracle": - column = column.upper() - conf.db = "USERS" - infoMsg = "searching column" if colConsider == "1": infoMsg += "s like" @@ -1417,29 +1484,7 @@ class Enumeration: foundCols[column] = {} - if kb.dbms == "Microsoft SQL Server": - if not conf.db: - if not len(kb.data.cachedDbs): - enumDbs = self.getDbs() - else: - enumDbs = kb.data.cachedDbs - - conf.db = ",".join(db for db in enumDbs) - - if conf.db: - for db in conf.db.split(","): - dbs[db] = {} - foundCols[column][db] = [] - - continue - - infoMsg = "fetching databases with tables containing column" - if colConsider == "1": - infoMsg += "s like" - infoMsg += " '%s'" % column - logger.info(infoMsg) - - if conf.excludeSysDbs and kb.dbms != "Oracle": + if conf.excludeSysDbs: exclDbsQuery = "".join(" AND '%s' != %s" % (db, dbCond) for db in self.excludeDbsList) infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList) logger.info(infoMsg) @@ -1459,9 +1504,29 @@ class Enumeration: if isinstance(values, str): values = [ values ] - for value in values: - dbs[value] = {} - foundCols[column][value] = [] + for foundDb, foundTbl in values: + if foundDb not in dbs: + dbs[foundDb] = {} + + if foundTbl not in dbs[foundDb]: + dbs[foundDb][foundTbl] = {} + + if colConsider == "1": + conf.db = foundDb + conf.tbl = foundTbl + conf.col = column + + self.getColumns(onlyColNames=True) + + dbs[foundDb][foundTbl].update(kb.data.cachedColumns[foundDb][foundTbl]) + kb.data.cachedColumns = {} + else: + dbs[foundDb][foundTbl][column] = None + + if foundDb in foundCols[column]: + foundCols[column][foundDb].append(foundTbl) + else: + foundCols[column][foundDb] = [ foundTbl ] else: infoMsg = "fetching number of databases with tables containing column" if colConsider == "1": @@ -1491,193 +1556,67 @@ class Enumeration: query += exclDbsQuery query = agent.limitQuery(index, query) db = inject.getValue(query, inband=False) - dbs[db] = {} - foundCols[column][db] = [] - for column, dbData in foundCols.items(): - colQuery = "%s%s" % (colCond, colCondParam) - colQuery = colQuery % column + if db not in dbs: + dbs[db] = {} - for db in dbData: - infoMsg = "fetching tables containing column" - if colConsider == "1": - infoMsg += "s like" - infoMsg += " '%s' in database '%s'" % (column, db) - logger.info(infoMsg) + if db not in foundCols[column]: + foundCols[column][db] = [] - if kb.unionPosition or conf.direct: - query = rootQuery["inband"]["query2"] + for column, dbData in foundCols.items(): + colQuery = "%s%s" % (colCond, colCondParam) + colQuery = colQuery % column - if kb.dbms in ( "MySQL", "PostgreSQL" ): - query = query % db - query += " AND %s" % colQuery - elif kb.dbms == "Oracle": - query += " WHERE %s" % colQuery - elif kb.dbms == "Microsoft SQL Server": - query = query % (db, db, db, db, db) - query += " AND %s" % colQuery.replace("[DB]", db) - - values = inject.getValue(query, blind=False) - - if values: - if isinstance(values, str): - values = [ values ] - - for value in values: - if value not in dbs[db]: - dbs[db][value] = {} - - dbs[db][value][column] = None - foundCols[column][db].append(value) - else: - infoMsg = "fetching number of tables containing column" - if colConsider == "1": - infoMsg += "s like" - infoMsg += " '%s' in database '%s'" % (column, db) - logger.info(infoMsg) - - query = rootQuery["blind"]["count2"] - - if kb.dbms in ( "MySQL", "PostgreSQL" ): - query = query % db - query += " AND %s" % colQuery - elif kb.dbms == "Oracle": - query += " WHERE %s" % colQuery - elif kb.dbms == "Microsoft SQL Server": - query = query % (db, db, db, db, db) - query += " AND %s" % colQuery.replace("[DB]", db) - - count = inject.getValue(query, inband=False, expected="int", charsetType=2) - - if not count.isdigit() or not len(count) or count == "0": - warnMsg = "no tables contain column" + for db in dbData: + infoMsg = "fetching number of tables containing column" if colConsider == "1": - warnMsg += "s like" - warnMsg += " '%s' " % column - warnMsg += "in database '%s'" % db - logger.warn(warnMsg) + infoMsg += "s like" + infoMsg += " '%s' in database '%s'" % (column, db) + logger.info(infoMsg) - continue + query = rootQuery["blind"]["count2"] + query = query % db + query += " AND %s" % colQuery + count = inject.getValue(query, inband=False, expected="int", charsetType=2) - indexRange = getRange(count) + if not count.isdigit() or not len(count) or count == "0": + warnMsg = "no tables contain column" + if colConsider == "1": + warnMsg += "s like" + warnMsg += " '%s' " % column + warnMsg += "in database '%s'" % db + logger.warn(warnMsg) - for index in indexRange: - query = rootQuery["blind"]["query2"] + continue - if kb.dbms in ( "MySQL", "PostgreSQL" ): + indexRange = getRange(count) + + for index in indexRange: + query = rootQuery["blind"]["query2"] query = query % db query += " AND %s" % colQuery - field = None - elif kb.dbms == "Oracle": - query += " WHERE %s" % colQuery - field = None - elif kb.dbms == "Microsoft SQL Server": - query = query % (db, db, db, db, db) - query += " AND %s" % colQuery.replace("[DB]", db) - field = colCond.replace("[DB]", db) + query = agent.limitQuery(index, query) + tbl = inject.getValue(query, inband=False) + kb.hintValue = tbl - query = agent.limitQuery(index, query, field) - tbl = inject.getValue(query, inband=False) + if tbl not in dbs[db]: + dbs[db][tbl] = {} - if tbl not in dbs[db]: - dbs[db][tbl] = {} + if colConsider == "1": + conf.db = db + conf.tbl = tbl + conf.col = column - dbs[db][tbl][column] = None - foundCols[column][db].append(tbl) + self.getColumns(onlyColNames=True) - if colConsider == "1": - okDbs = {} + dbs[db][tbl].update(kb.data.cachedColumns[db][tbl]) + kb.data.cachedColumns = {} + else: + dbs[db][tbl][column] = None - for db, tableData in dbs.items(): - conf.db = db - okDbs[db] = {} + foundCols[column][db].append(tbl) - for tbl, columns in tableData.items(): - conf.tbl = tbl - - for column in columns: - conf.col = column - - self.getColumns(onlyColNames=True) - - if tbl in okDbs[db]: - okDbs[db][tbl].update(kb.data.cachedColumns[db][tbl]) - else: - okDbs[db][tbl] = kb.data.cachedColumns[db][tbl] - - kb.data.cachedColumns = {} - - dbs = okDbs - - if not dbs: - warnMsg = "no databases have tables containing any of the " - warnMsg += "provided columns" - logger.warn(warnMsg) - return - - dumper.dbColumns(foundCols, colConsider, dbs) - - message = "do you want to dump entries? [Y/n] " - output = readInput(message, default="Y") - - if output and output[0] not in ("y", "Y"): - return - - dumpFromDbs = [] - message = "which database(s)?\n[a]ll (default)\n" - - for db, tblData in dbs.items(): - if tblData: - message += "[%s]\n" % db - - message += "[q]uit" - test = readInput(message, default="a") - - if not test or test in ("a", "A"): - dumpFromDbs = dbs.keys() - elif test in ("q", "Q"): - return - else: - dumpFromDbs = test.replace(" ", "").split(",") - - for db, tblData in dbs.items(): - if db not in dumpFromDbs or not tblData: - continue - - conf.db = db - dumpFromTbls = [] - message = "which table(s) of database '%s'?\n" % db - message += "[a]ll (default)\n" - - for tbl in tblData: - message += "[%s]\n" % tbl - - message += "[s]kip\n" - message += "[q]uit" - test = readInput(message, default="a") - - if not test or test in ("a", "A"): - dumpFromTbls = tblData - elif test in ("s", "S"): - continue - elif test in ("q", "Q"): - return - else: - dumpFromTbls = test.replace(" ", "").split(",") - - for table, columns in tblData.items(): - if table not in dumpFromTbls: - continue - - conf.tbl = table - conf.col = ",".join(column for column in columns) - kb.data.cachedColumns = {} - kb.data.dumpedTable = {} - - data = self.dumpTable() - - if data: - dumper.dbTableValues(data) + self.dumpFoundColumn(dbs, foundCols, colConsider) def search(self): if conf.db: diff --git a/xml/queries.xml b/xml/queries.xml index 8235e4aaa..e38418fcf 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -68,7 +68,7 @@ - + @@ -145,8 +145,8 @@ - - + + @@ -217,7 +217,7 @@ - + @@ -280,7 +280,7 @@ - +