From a7fa8d49754be6f832940dc970f17f90d8bbf9d0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 9 Nov 2010 16:15:55 +0000 Subject: [PATCH] update regarding brute force retrieval of table names and table column names --- lib/controller/action.py | 9 +-- lib/core/dump.py | 137 +++++++++++++++++++++--------------- lib/parse/cmdline.py | 12 +++- lib/techniques/brute/use.py | 15 ++-- 4 files changed, 106 insertions(+), 67 deletions(-) diff --git a/lib/controller/action.py b/lib/controller/action.py index 83e1bbf09..465cb464a 100644 --- a/lib/controller/action.py +++ b/lib/controller/action.py @@ -16,6 +16,7 @@ from lib.core.data import paths from lib.core.exception import sqlmapUnsupportedDBMSException from lib.core.settings import SUPPORTED_DBMS from lib.techniques.blind.timebased import timeTest +from lib.techniques.brute.use import columnExists from lib.techniques.brute.use import tableExists from lib.techniques.error.test import errorTest from lib.techniques.inband.union.test import unionTest @@ -105,15 +106,15 @@ def action(): if conf.getTables: conf.dumper.dbTables(conf.dbmsHandler.getTables()) - if conf.cExists: + if conf.bruteTables: conf.dumper.dbTables(tableExists(paths.COMMON_TABLES)) - if conf.tableFile: - conf.dumper.dbTables(tableExists(conf.tableFile)) - if conf.getColumns: conf.dumper.dbTableColumns(conf.dbmsHandler.getColumns()) + if conf.bruteColumns: + conf.dumper.dbTableColumns(columnExists(paths.COMMON_COLUMNS)) + if conf.dumpTable: conf.dumper.dbTableValues(conf.dbmsHandler.dumpTable()) diff --git a/lib/core/dump.py b/lib/core/dump.py index 96b439cdf..e51450239 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -148,7 +148,7 @@ class Dump: dbTables.sort(key=lambda x: x.lower()) - self.__write("Brute-forced tables:") + self.__write("Brute-forced table names:") if len(dbTables) == 1: self.__write("[1 table]") @@ -199,69 +199,96 @@ class Dump: self.string("tables", dbTables) def dbTableColumns(self, tableColumns): - for db, tables in tableColumns.items(): - if not db: - db = "All" + if isinstance(tableColumns, list) and len(tableColumns) > 0: + maxlength = 0 - for table, columns in tables.items(): - maxlength1 = 0 - maxlength2 = 0 + for table in tableColumns: + maxlength = max(maxlength, len(table)) - colList = columns.keys() - colList.sort(key=lambda x: x.lower()) + lines = "-" * (int(maxlength) + 2) - for column in colList: - colType = columns[column] - maxlength1 = max(maxlength1, len(column)) + tableColumns.sort(key=lambda x: x.lower()) + + self.__write("Brute-forced column names for table '%s':" % conf.tbl) + + if len(tableColumns) == 1: + self.__write("[1 column]") + else: + self.__write("[%d columns]" % len(tableColumns)) + + self.__write("+%s+" % lines) + + for table in tableColumns: + blank = " " * (maxlength - len(table)) + self.__write("| %s%s |" % (table, blank)) + + self.__write("+%s+\n" % lines) + + elif isinstance(tableColumns, dict) and len(tableColumns) > 0: + + for db, tables in tableColumns.items(): + if not db: + db = "All" + + for table, columns in tables.items(): + maxlength1 = 0 + maxlength2 = 0 + + colList = columns.keys() + colList.sort(key=lambda x: x.lower()) + + for column in colList: + colType = columns[column] + maxlength1 = max(maxlength1, len(column)) + + if colType is not None: + maxlength2 = max(maxlength2, len(colType)) + + maxlength1 = max(maxlength1, len("COLUMN")) + lines1 = "-" * (int(maxlength1) + 2) if colType is not None: - maxlength2 = max(maxlength2, len(colType)) + maxlength2 = max(maxlength2, len("TYPE")) + lines2 = "-" * (int(maxlength2) + 2) - maxlength1 = max(maxlength1, len("COLUMN")) - lines1 = "-" * (int(maxlength1) + 2) + self.__write("Database: %s\nTable: %s" % (db, table)) - if colType is not None: - maxlength2 = max(maxlength2, len("TYPE")) - lines2 = "-" * (int(maxlength2) + 2) - - self.__write("Database: %s\nTable: %s" % (db, table)) - - if len(columns) == 1: - self.__write("[1 column]") - else: - self.__write("[%d columns]" % len(columns)) - - if colType is not None: - self.__write("+%s+%s+" % (lines1, lines2)) - else: - self.__write("+%s+" % lines1) - - blank1 = " " * (maxlength1 - len("COLUMN")) - - if colType is not None: - blank2 = " " * (maxlength2 - len("TYPE")) - - if colType is not None: - self.__write("| Column%s | Type%s |" % (blank1, blank2)) - self.__write("+%s+%s+" % (lines1, lines2)) - else: - self.__write("| Column%s |" % blank1) - self.__write("+%s+" % lines1) - - for column in colList: - colType = columns[column] - blank1 = " " * (maxlength1 - len(column)) - - if colType is not None: - blank2 = " " * (maxlength2 - len(colType)) - self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2)) + if len(columns) == 1: + self.__write("[1 column]") else: - self.__write("| %s%s |" % (column, blank1)) + self.__write("[%d columns]" % len(columns)) - if colType is not None: - self.__write("+%s+%s+\n" % (lines1, lines2)) - else: - self.__write("+%s+\n" % lines1) + if colType is not None: + self.__write("+%s+%s+" % (lines1, lines2)) + else: + self.__write("+%s+" % lines1) + + blank1 = " " * (maxlength1 - len("COLUMN")) + + if colType is not None: + blank2 = " " * (maxlength2 - len("TYPE")) + + if colType is not None: + self.__write("| Column%s | Type%s |" % (blank1, blank2)) + self.__write("+%s+%s+" % (lines1, lines2)) + else: + self.__write("| Column%s |" % blank1) + self.__write("+%s+" % lines1) + + for column in colList: + colType = columns[column] + blank1 = " " * (maxlength1 - len(column)) + + if colType is not None: + blank2 = " " * (maxlength2 - len(colType)) + self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2)) + else: + self.__write("| %s%s |" % (column, blank1)) + + if colType is not None: + self.__write("+%s+%s+\n" % (lines1, lines2)) + else: + self.__write("+%s+\n" % lines1) def dbTableValues(self, tableValues): replication = None diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 661755976..0272affd5 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -341,11 +341,16 @@ def cmdLineParser(): action="store_true", default=False, help="Prompt for an interactive SQL shell") - enumeration.add_option("--common-exists", dest="cExists", action="store_true", + # User-defined function options + brute = OptionGroup(parser, "Brute force", "These " + "options can be used to run brute force " + "checks.") + + brute.add_option("--brute-tables", dest="bruteTables", action="store_true", default=False, help="Check existence of common tables") - enumeration.add_option("--exists", dest="tableFile", - help="Check existence of user specified tables") + brute.add_option("--brute-columns", dest="bruteColumns", action="store_true", + default=False, help="Check existence of common columns") # User-defined function options udf = OptionGroup(parser, "User-defined function injection", "These " @@ -526,6 +531,7 @@ def cmdLineParser(): parser.add_option_group(techniques) parser.add_option_group(fingerprint) parser.add_option_group(enumeration) + parser.add_option_group(brute) parser.add_option_group(udf) parser.add_option_group(filesystem) parser.add_option_group(takeover) diff --git a/lib/techniques/brute/use.py b/lib/techniques/brute/use.py index d34af6202..e1bdc06be 100644 --- a/lib/techniques/brute/use.py +++ b/lib/techniques/brute/use.py @@ -19,6 +19,7 @@ from lib.core.common import randomInt from lib.core.common import safeStringFormat from lib.core.data import conf from lib.core.data import logger +from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.request.connect import Connect as Request def tableExists(tableFile): @@ -57,19 +58,23 @@ def tableExists(tableFile): return retVal -def columnExists(table, columnFile): - tables = getFileItems(columnFile, None) +def columnExists(columnFile): + if not conf.tbl: + errMsg = "missing table parameter" + raise sqlmapMissingMandatoryOptionException, errMsg + + columns = getFileItems(columnFile, None) retVal = [] - infoMsg = "checking column existence for table '%s' using items from '%s'" % (table, columnFile) + infoMsg = "checking column existence for table '%s' using items from '%s'" % (conf.tbl, columnFile) logger.info(infoMsg) pushValue(conf.verbose) conf.verbose = 0 count = 0 - length = len(tables) + length = len(columns) for column in columns: - query = agent.prefixQuery("%s" % safeStringFormat("AND EXISTS(SELECT %s FROM %s)", (column, table))) + query = agent.prefixQuery("%s" % safeStringFormat("AND EXISTS(SELECT %s FROM %s)", (column, conf.tbl))) query = agent.postfixQuery(query) result = Request.queryPage(agent.payload(newValue=query))