def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter. sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) columns" logger.warn(warnMsg) conf.db = self.getCurrentDb() elif conf.db is not None: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.db = conf.db.upper() if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise sqlmapMissingMandatoryOptionException, errMsg conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.col = conf.col.upper() colList = conf.col.split(",") else: colList = [] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) colList = filter(None, colList) if conf.tbl: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(",") else: self.getTables() if len(kb.data.cachedTables) > 0: if conf.db in kb.data.cachedTables: tblList = kb.data.cachedTables[conf.db] else: tblList = kb.data.cachedTables.values() if isinstance(tblList[0], (set, tuple, list)): tblList = tblList[0] tblList = list(tblList) else: errMsg = "unable to retrieve the tables " errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) raise sqlmapNoneDataException, errMsg for tbl in tblList: tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True) if bruteForce is None: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" logger.error(errMsg) bruteForce = True elif Backend.isDbms(DBMS.ACCESS): errMsg = "cannot retrieve column names, " errMsg += "back-end DBMS is Access" logger.error(errMsg) bruteForce = True if bruteForce or colList: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable or colList: columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns} return kb.data.cachedColumns message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS,) else "[y/N/q]") test = readInput(message, default="Y" if "Y" in message else "N") if test[0] in ("n", "N"): return elif test[0] in ("q", "Q"): raise sqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[Backend.getIdentifiedDbms()].columns condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR)) or conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " if len(colList) > 0: if colTuple is None: colConsider, colCondParam = self.likeOrExact("column") else: colConsider, colCondParam = colTuple condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if colConsider == "1": infoMsg += "like '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: condQuery = "" infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.inband.query % unsafeSQLIdentificatorNaming(tbl.upper()) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.inband.query % tbl value = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.SQLITE): parseSqliteTableSchema(unArrayizeValue(value)) elif not isNoneValue(value): table = {} columns = {} for columnData in value: if not isNoneValue(columnData): name = safeSQLIdentificatorNaming(columnData[0]) if name: if len(columnData) == 1: columns[name] = "" else: columns[name] = columnData[1] if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table elif isInferenceAvailable() and not conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % conf.db logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " if len(colList) > 0: if colTuple is None: colConsider, colCondParam = self.likeOrExact("column") else: colConsider, colCondParam = colTuple condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if colConsider == "1": infoMsg += "like '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: condQuery = "" infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.count % unsafeSQLIdentificatorNaming(tbl.upper()) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.count % (conf.db, conf.db, \ unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.count % (tbl) query += condQuery elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % tbl value = inject.getValue(query, union=False, error=False) parseSqliteTableSchema(value) return kb.data.cachedColumns count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): errMsg = "unable to retrieve the number of columns " errMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.error(errMsg) continue table = {} columns = {} for index in getLimitRange(count): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query % unsafeSQLIdentificatorNaming(tbl.upper()) query += condQuery field = None elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query.replace("'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1]).replace("%s", conf.db).replace("%d", str(index)) query += condQuery.replace("[DB]", conf.db) field = condition.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (tbl) query += condQuery field = None query = agent.limitQuery(index, query, field, field) column = inject.getValue(query, union=False, error=False) if not isNoneValue(column): if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query2 % (tbl, column) colType = inject.getValue(query, union=False, error=False) if Backend.isDbms(DBMS.FIREBIRD): colType = FIREBIRD_TYPES.get(colType, colType) column = safeSQLIdentificatorNaming(column) columns[column] = colType else: column = safeSQLIdentificatorNaming(column) columns[column] = None if columns: if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table if not kb.data.cachedColumns: errMsg = "unable to retrieve column names for " errMsg += ("table '%s' " % tblList[0]) if len(tblList) == 1 else "any table " errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.error(errMsg) if bruteForce is None: return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True) return kb.data.cachedColumns
def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter. sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) columns" logger.warn(warnMsg) conf.db = self.getCurrentDb() if not conf.db: errMsg = "unable to retrieve the current " errMsg += "database name" raise SqlmapNoneDataException(errMsg) elif conf.db is not None: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): conf.db = conf.db.upper() if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.col = conf.col.upper() colList = conf.col.split(',') else: colList = [] if conf.excludeCol: colList = [_ for _ in colList if _ not in conf.excludeCol.split(',')] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) colList = filter(None, colList) if conf.tbl: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(",") else: self.getTables() if len(kb.data.cachedTables) > 0: if conf.db in kb.data.cachedTables: tblList = kb.data.cachedTables[conf.db] else: tblList = kb.data.cachedTables.values() if isinstance(tblList[0], (set, tuple, list)): tblList = tblList[0] tblList = list(tblList) elif not conf.search: errMsg = "unable to retrieve the tables " errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) raise SqlmapNoneDataException(errMsg) else: return kb.data.cachedColumns tblList = filter(None, (safeSQLIdentificatorNaming(_, True) for _ in tblList)) if bruteForce is None: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" logger.error(errMsg) bruteForce = True elif Backend.isDbms(DBMS.ACCESS): errMsg = "cannot retrieve column names, " errMsg += "back-end DBMS is %s" % DBMS.ACCESS logger.error(errMsg) bruteForce = True if bruteForce: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable and not conf.freshQueries or colList: columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns} return kb.data.cachedColumns message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS,) else "[y/N/q]") test = readInput(message, default="Y" if "Y" in message else "N") if test[0] in ("n", "N"): return elif test[0] in ("q", "Q"): raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[Backend.getIdentifiedDbms()].columns condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.inband.query % tbl if dumpMode and colList: values = [(_,) for _ in colList] else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) values = None if Backend.isDbms(DBMS.MSSQL) and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): expression = query kb.dumpColumns = [] kb.rowXmlMode = True for column in extractRegexResult(r"SELECT (?P<result>.+?) FROM", query).split(','): kb.dumpColumns.append(randomStr().lower()) expression = expression.replace(column, "%s AS %s" % (column, kb.dumpColumns[-1]), 1) values = unionUse(expression) kb.rowXmlMode = False kb.dumpColumns = None if values is None: values = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): index, values = 1, [] while True: query = rootQuery.inband.query2 % (conf.db, tbl, index) value = unArrayizeValue(inject.getValue(query, blind=False, time=False)) if isNoneValue(value) or value == " ": break else: values.append((value,)) index += 1 if Backend.isDbms(DBMS.SQLITE): parseSqliteTableSchema(unArrayizeValue(values)) elif not isNoneValue(values): table = {} columns = {} for columnData in values: if not isNoneValue(columnData): name = safeSQLIdentificatorNaming(columnData[0]) if name: if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name)) comment = unArrayizeValue(inject.getValue(query, blind=False, time=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % (comment, name) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if len(columnData) == 1: columns[name] = None else: if Backend.isDbms(DBMS.FIREBIRD): columnData[1] = FIREBIRD_TYPES.get(int(columnData[1]) if isinstance(columnData[1], basestring) and columnData[1].isdigit() else columnData[1], columnData[1]) columns[name] = columnData[1] if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table elif isInferenceAvailable() and not conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.count % (conf.db, conf.db, \ unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.count % (tbl) query += condQuery elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % tbl value = unArrayizeValue(inject.getValue(query, union=False, error=False)) parseSqliteTableSchema(value) return kb.data.cachedColumns table = {} columns = {} if dumpMode and colList: count = 0 for value in colList: columns[safeSQLIdentificatorNaming(value)] = None else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if Backend.isDbms(DBMS.MSSQL): count, index, values = 0, 1, [] while True: query = rootQuery.blind.query3 % (conf.db, tbl, index) value = unArrayizeValue(inject.getValue(query, union=False, error=False)) if isNoneValue(value) or value == " ": break else: columns[safeSQLIdentificatorNaming(value)] = None index += 1 if not columns: errMsg = "unable to retrieve the %scolumns " % ("number of " if not Backend.isDbms(DBMS.MSSQL) else "") errMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.error(errMsg) continue for index in getLimitRange(count): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query.replace("'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1]).replace("%s", conf.db).replace("%d", str(index)) query += condQuery.replace("[DB]", conf.db) field = condition.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (tbl) query += condQuery field = None query = agent.limitQuery(index, query, field, field) column = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(column): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column)) comment = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % (comment, column) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query2 % (tbl, column) colType = unArrayizeValue(inject.getValue(query, union=False, error=False)) if Backend.isDbms(DBMS.FIREBIRD): colType = FIREBIRD_TYPES.get(colType, colType) column = safeSQLIdentificatorNaming(column) columns[column] = colType else: column = safeSQLIdentificatorNaming(column) columns[column] = None if columns: if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table if not kb.data.cachedColumns: warnMsg = "unable to retrieve column names for " warnMsg += ("table '%s' " % unsafeSQLIdentificatorNaming(unArrayizeValue(tblList))) if len(tblList) == 1 else "any table " warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.warn(warnMsg) if bruteForce is None: return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True) return kb.data.cachedColumns
def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter, sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) columns" logger.warn(warnMsg) conf.db = self.getCurrentDb() elif conf.db is not None: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.db = conf.db.upper() if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise sqlmapMissingMandatoryOptionException, errMsg conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.col = conf.col.upper() colList = conf.col.split(",") else: colList = [] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) colList = filter(None, colList) if conf.tbl: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(",") else: self.getTables() if len(kb.data.cachedTables) > 0: if conf.db in kb.data.cachedTables: tblList = kb.data.cachedTables[conf.db] else: tblList = kb.data.cachedTables.values() if isinstance(tblList[0], (set, tuple, list)): tblList = tblList[0] tblList = list(tblList) else: errMsg = "unable to retrieve the tables " errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) raise sqlmapNoneDataException, errMsg for tbl in tblList: tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True) if bruteForce is None: if Backend.isDbms( DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" logger.error(errMsg) bruteForce = True elif Backend.isDbms(DBMS.ACCESS): errMsg = "cannot retrieve column names, " errMsg += "back-end DBMS is Access" logger.error(errMsg) bruteForce = True if bruteForce or colList: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable or colList: columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)][safeSQLIdentificatorNaming( tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)] = { safeSQLIdentificatorNaming(tbl, True): columns } return kb.data.cachedColumns message = "do you want to use common column existence check? %s" % ( "[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, ) else "[y/N/q]") test = readInput(message, default="Y" if "Y" in message else "N") if test[0] in ("n", "N"): return elif test[0] in ("q", "Q"): raise sqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[Backend.getIdentifiedDbms()].columns condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None if any( isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR)) or conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " if len(colList) > 0: if colTuple is None: colConsider, colCondParam = self.likeOrExact("column") else: colConsider, colCondParam = colTuple condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join( condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if colConsider == "1": infoMsg += "like '%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: infoMsg += "'%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: condQuery = "" infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming( tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.info(infoMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.inband.query % ( unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.inband.query % unsafeSQLIdentificatorNaming( tbl.upper()) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.inband.query % ( conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.inband.query % tbl value = inject.getValue(query, blind=False) if Backend.isDbms(DBMS.SQLITE): parseSqliteTableSchema(value) elif not isNoneValue(value): table = {} columns = {} for columnData in value: if not isNoneValue(columnData): name = safeSQLIdentificatorNaming(columnData[0]) if name: if len(columnData) == 1: columns[name] = "" else: columns[name] = columnData[1] if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)][safeSQLIdentificatorNaming( tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)] = table elif isInferenceAvailable() and not conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % conf.db logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " if len(colList) > 0: if colTuple is None: colConsider, colCondParam = self.likeOrExact("column") else: colConsider, colCondParam = colTuple condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join( condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if colConsider == "1": infoMsg += "like '%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: infoMsg += "'%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: condQuery = "" infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming( tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.info(infoMsg) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.count % ( unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.count % unsafeSQLIdentificatorNaming( tbl.upper()) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.count % (conf.db, conf.db, \ unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.count % (tbl) query += condQuery elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % tbl value = inject.getValue(query, inband=False, error=False) parseSqliteTableSchema(value) return kb.data.cachedColumns count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): errMsg = "unable to retrieve the number of columns " errMsg += "for table '%s' " % unsafeSQLIdentificatorNaming( tbl) errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.error(errMsg) continue table = {} columns = {} for index in getLimitRange(count): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.query % ( unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query % unsafeSQLIdentificatorNaming( tbl.upper()) query += condQuery field = None elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query.replace( "'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1] ).replace("%s", conf.db).replace("%d", str(index)) query += condQuery.replace("[DB]", conf.db) field = condition.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (tbl) query += condQuery field = None query = agent.limitQuery(index, query, field, field) column = inject.getValue(query, inband=False, error=False) if not isNoneValue(column): if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.query2 % ( unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query2 % ( unsafeSQLIdentificatorNaming( tbl.upper()), column) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % ( conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split( ".")[-1]) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query2 % (tbl, column) colType = inject.getValue(query, inband=False, error=False) if Backend.isDbms(DBMS.FIREBIRD): colType = FIREBIRD_TYPES.get(colType, colType) column = safeSQLIdentificatorNaming(column) columns[column] = colType else: column = safeSQLIdentificatorNaming(column) columns[column] = None if columns: if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)][safeSQLIdentificatorNaming( tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)] = table if not kb.data.cachedColumns: errMsg = "unable to retrieve the columns for any " errMsg += "table in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.error(errMsg) if bruteForce is None: return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True) return kb.data.cachedColumns
def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = "missing database parameter. sqlmap is going " warnMsg += "to use the current database to enumerate " warnMsg += "table(s) columns" logger.warn(warnMsg) conf.db = self.getCurrentDb() if not conf.db: errMsg = "unable to retrieve the current " errMsg += "database name" raise SqlmapNoneDataException(errMsg) elif conf.db is not None: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): conf.db = conf.db.upper() if ',' in conf.db: errMsg = "only one database name is allowed when enumerating " errMsg += "the tables' columns" raise SqlmapMissingMandatoryOptionException(errMsg) conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.col = conf.col.upper() colList = conf.col.split(',') else: colList = [] if conf.excludeCol: colList = [_ for _ in colList if _ not in conf.excludeCol.split(',')] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) colList = filter(None, colList) if conf.tbl: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(",") else: self.getTables() if len(kb.data.cachedTables) > 0: if conf.db in kb.data.cachedTables: tblList = kb.data.cachedTables[conf.db] else: tblList = kb.data.cachedTables.values() if isinstance(tblList[0], (set, tuple, list)): tblList = tblList[0] tblList = list(tblList) elif not conf.search: errMsg = "unable to retrieve the tables " errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) raise SqlmapNoneDataException(errMsg) else: return kb.data.cachedColumns tblList = filter(None, (safeSQLIdentificatorNaming(_, True) for _ in tblList)) if bruteForce is None: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" logger.error(errMsg) bruteForce = True elif Backend.isDbms(DBMS.ACCESS): errMsg = "cannot retrieve column names, " errMsg += "back-end DBMS is %s" % DBMS.ACCESS logger.error(errMsg) bruteForce = True if bruteForce: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable and not conf.freshQueries or colList: columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns} return kb.data.cachedColumns message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS,) else "[y/N/q]") test = readInput(message, default="Y" if "Y" in message else "N") if test[0] in ("n", "N"): return elif test[0] in ("q", "Q"): raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[Backend.getIdentifiedDbms()].columns condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.inband.query % tbl if dumpMode and colList: values = [(_,) for _ in colList] else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) values = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): index, values = 1, [] while True: query = rootQuery.inband.query2 % (conf.db, tbl, index) value = unArrayizeValue(inject.getValue(query, blind=False, time=False)) if isNoneValue(value) or value == " ": break else: values.append((value,)) index += 1 if Backend.isDbms(DBMS.SQLITE): parseSqliteTableSchema(unArrayizeValue(values)) elif not isNoneValue(values): table = {} columns = {} for columnData in values: if not isNoneValue(columnData): name = safeSQLIdentificatorNaming(columnData[0]) if name: if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name)) comment = unArrayizeValue(inject.getValue(query, blind=False, time=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % (comment, name) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if len(columnData) == 1: columns[name] = None else: if Backend.isDbms(DBMS.FIREBIRD): columnData[1] = FIREBIRD_TYPES.get(int(columnData[1]) if isinstance(columnData[1], basestring) and columnData[1].isdigit() else columnData[1], columnData[1]) columns[name] = columnData[1] if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table elif isInferenceAvailable() and not conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.count % (conf.db, conf.db, \ unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.count % (tbl) query += condQuery elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % tbl value = unArrayizeValue(inject.getValue(query, union=False, error=False)) parseSqliteTableSchema(value) return kb.data.cachedColumns table = {} columns = {} if dumpMode and colList: count = 0 for value in colList: columns[safeSQLIdentificatorNaming(value)] = None else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if Backend.isDbms(DBMS.MSSQL): count, index, values = 0, 1, [] while True: query = rootQuery.blind.query3 % (conf.db, tbl, index) value = unArrayizeValue(inject.getValue(query, union=False, error=False)) if isNoneValue(value) or value == " ": break else: columns[safeSQLIdentificatorNaming(value)] = None index += 1 if not columns: errMsg = "unable to retrieve the %scolumns " % ("number of " if not Backend.isDbms(DBMS.MSSQL) else "") errMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl) errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.error(errMsg) continue for index in getLimitRange(count): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query.replace("'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1]).replace("%s", conf.db).replace("%d", str(index)) query += condQuery.replace("[DB]", conf.db) field = condition.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (tbl) query += condQuery field = None query = agent.limitQuery(index, query, field, field) column = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(column): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column)) comment = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % (comment, column) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms() warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query2 % (tbl, column) colType = unArrayizeValue(inject.getValue(query, union=False, error=False)) if Backend.isDbms(DBMS.FIREBIRD): colType = FIREBIRD_TYPES.get(colType, colType) column = safeSQLIdentificatorNaming(column) columns[column] = colType else: column = safeSQLIdentificatorNaming(column) columns[column] = None if columns: if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table if not kb.data.cachedColumns: warnMsg = "unable to retrieve column names for " warnMsg += ("table '%s' " % unsafeSQLIdentificatorNaming(unArrayizeValue(tblList))) if len(tblList) == 1 else "any table " warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.warn(warnMsg) if bruteForce is None: return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True) return kb.data.cachedColumns
def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False): self.forceDbmsEnum() if conf.db is None or conf.db == CURRENT_DB: if conf.db is None: warnMsg = u"缺少数据库参数,sqlmap将使用当前数据库枚举表中的字段" logger.warn(warnMsg) conf.db = self.getCurrentDb() if not conf.db: errMsg = u"无法检索当前数据库名称" raise SqlmapNoneDataException(errMsg) elif conf.db is not None: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): conf.db = conf.db.upper() if ',' in conf.db: errMsg = u"枚举表列时只允许一个数据库名称" raise SqlmapMissingMandatoryOptionException(errMsg) conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.col = conf.col.upper() colList = conf.col.split(',') else: colList = [] if conf.excludeCol: colList = [ _ for _ in colList if _ not in conf.excludeCol.split(',') ] for col in colList: colList[colList.index(col)] = safeSQLIdentificatorNaming(col) colList = filter(None, colList) if conf.tbl: if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(',') else: self.getTables() if len(kb.data.cachedTables) > 0: if conf.db in kb.data.cachedTables: tblList = kb.data.cachedTables[conf.db] else: tblList = kb.data.cachedTables.values() if isinstance(tblList[0], (set, tuple, list)): tblList = tblList[0] tblList = list(tblList) elif not conf.search: errMsg = u"无法检索数据库'%s'中的表" % unsafeSQLIdentificatorNaming( conf.db) raise SqlmapNoneDataException(errMsg) else: return kb.data.cachedColumns tblList = filter(None, (safeSQLIdentificatorNaming(_, True) for _ in tblList)) if bruteForce is None: if Backend.isDbms( DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = u"information_schema不可用,后端DBMS是MySQL < 5.0" logger.error(errMsg) bruteForce = True elif Backend.isDbms(DBMS.ACCESS): errMsg = u"无法检索列名,后端DBMS为 %s" % DBMS.ACCESS logger.error(errMsg) bruteForce = True if bruteForce: resumeAvailable = False for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: resumeAvailable = True break if resumeAvailable and not conf.freshQueries or colList: columns = {} for column in colList: columns[column] = None for tbl in tblList: for db, table, colName, colType in kb.brute.columns: if db == conf.db and table == tbl: columns[colName] = colType if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)][safeSQLIdentificatorNaming( tbl, True)] = columns else: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)] = { safeSQLIdentificatorNaming(tbl, True): columns } return kb.data.cachedColumns message = "do you want to use common column existence check? %s" % ( "[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, ) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': return elif choice == 'Q': raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) rootQuery = queries[Backend.getIdentifiedDbms()].columns condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None if any( isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = u"在数据库'%s'上获取表的字段" % unsafeSQLIdentificatorNaming( conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = u"获取字段 " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join( condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.inband.query % ( unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.inband.query % ( unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.inband.query % ( conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.inband.query % tbl if dumpMode and colList: values = [(_, ) for _ in colList] else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming( tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.info(infoMsg) values = None if Backend.isDbms(DBMS.MSSQL) and isTechniqueAvailable( PAYLOAD.TECHNIQUE.UNION): expression = query kb.dumpColumns = [] kb.rowXmlMode = True for column in extractRegexResult( r"SELECT (?P<result>.+?) FROM", query).split(','): kb.dumpColumns.append(randomStr().lower()) expression = expression.replace( column, "%s AS %s" % (column, kb.dumpColumns[-1]), 1) values = unionUse(expression) kb.rowXmlMode = False kb.dumpColumns = None if values is None: values = inject.getValue(query, blind=False, time=False) if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values): index, values = 1, [] while True: query = rootQuery.inband.query2 % (conf.db, tbl, index) value = unArrayizeValue( inject.getValue(query, blind=False, time=False)) if isNoneValue(value) or value == " ": break else: values.append((value, )) index += 1 if Backend.isDbms(DBMS.SQLITE): parseSqliteTableSchema(unArrayizeValue(values)) elif not isNoneValue(values): table = {} columns = {} for columnData in values: if not isNoneValue(columnData): name = safeSQLIdentificatorNaming(columnData[0]) if name: if conf.getComments: _ = queries[Backend.getIdentifiedDbms( )].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in ( DBMS.ORACLE, DBMS.DB2): query = _.query % ( unsafeSQLIdentificatorNaming( conf.db.upper()), unsafeSQLIdentificatorNaming( tbl.upper()), unsafeSQLIdentificatorNaming( name.upper())) else: query = _.query % ( unsafeSQLIdentificatorNaming( conf.db), unsafeSQLIdentificatorNaming( tbl), unsafeSQLIdentificatorNaming( name)) comment = unArrayizeValue( inject.getValue(query, blind=False, time=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % ( comment, name) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms( ) warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if len(columnData) == 1: columns[name] = None else: key = int(columnData[1]) if isinstance( columnData[1], basestring) and columnData[1].isdigit( ) else columnData[1] if Backend.isDbms(DBMS.FIREBIRD): columnData[1] = FIREBIRD_TYPES.get( key, columnData[1]) elif Backend.isDbms(DBMS.INFORMIX): notNull = False if isinstance(key, int) and key > 255: key -= 256 notNull = True columnData[1] = INFORMIX_TYPES.get( key, columnData[1]) if notNull: columnData[ 1] = "%s NOT NULL" % columnData[ 1] columns[name] = columnData[1] if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)][safeSQLIdentificatorNaming( tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)] = table elif isInferenceAvailable() and not conf.direct: for tbl in tblList: if conf.db is not None and len(kb.data.cachedColumns) > 0 \ and conf.db in kb.data.cachedColumns and tbl in \ kb.data.cachedColumns[conf.db]: infoMsg = "fetched tables' columns on " infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.info(infoMsg) return {conf.db: kb.data.cachedColumns[conf.db]} infoMsg = "fetching columns " condQuery = "" if len(colList) > 0: if colTuple: _, colCondParam = colTuple infoMsg += "LIKE '%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) else: colCondParam = "='%s'" infoMsg += "'%s' " % ", ".join( unsafeSQLIdentificatorNaming(col) for col in sorted(colList)) condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join( condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.blind.count % ( unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.count % ( unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.count % (conf.db, conf.db, \ unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) query += condQuery.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.count % (tbl) query += condQuery elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.count % (conf.db, conf.db, conf.db, conf.db, conf.db, tbl) query += condQuery elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % tbl value = unArrayizeValue( inject.getValue(query, union=False, error=False)) parseSqliteTableSchema(value) return kb.data.cachedColumns table = {} columns = {} if dumpMode and colList: count = 0 for value in colList: columns[safeSQLIdentificatorNaming(value)] = None else: infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming( tbl) infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.info(infoMsg) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if Backend.isDbms(DBMS.MSSQL): count, index, values = 0, 1, [] while True: query = rootQuery.blind.query3 % (conf.db, tbl, index) value = unArrayizeValue( inject.getValue(query, union=False, error=False)) if isNoneValue(value) or value == " ": break else: columns[safeSQLIdentificatorNaming( value)] = None index += 1 if not columns: errMsg = "unable to retrieve the %scolumns " % ( "number of " if not Backend.isDbms(DBMS.MSSQL) else "") errMsg += "for table '%s' " % unsafeSQLIdentificatorNaming( tbl) errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.error(errMsg) continue for index in getLimitRange(count): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): query = rootQuery.blind.query % ( unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query % ( unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query.replace( "'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1] ).replace("%s", conf.db).replace("%d", str(index)) query += condQuery.replace("[DB]", conf.db) field = condition.replace("[DB]", conf.db) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (tbl) query += condQuery field = None elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (index, conf.db, conf.db, conf.db, conf.db, conf.db, tbl) query += condQuery field = condition query = agent.limitQuery(index, query, field, field) column = unArrayizeValue( inject.getValue(query, union=False, error=False)) if not isNoneValue(column): if conf.getComments: _ = queries[ Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = _.query % ( unsafeSQLIdentificatorNaming( conf.db.upper()), unsafeSQLIdentificatorNaming( tbl.upper()), unsafeSQLIdentificatorNaming( column.upper())) else: query = _.query % ( unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column)) comment = unArrayizeValue( inject.getValue(query, union=False, error=False)) if not isNoneValue(comment): infoMsg = "retrieved comment '%s' for column '%s'" % ( comment, column) logger.info(infoMsg) else: warnMsg = "on %s it is not " % Backend.getIdentifiedDbms( ) warnMsg += "possible to get column comments" singleTimeWarnMessage(warnMsg) if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): query = rootQuery.blind.query2 % ( unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query2 % ( unsafeSQLIdentificatorNaming( tbl.upper()), column, unsafeSQLIdentificatorNaming( conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % ( conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split( ".")[-1]) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query2 % (tbl, column) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query2 % ( conf.db, conf.db, conf.db, conf.db, conf.db, tbl, column) colType = unArrayizeValue( inject.getValue(query, union=False, error=False)) key = int(colType) if isinstance( colType, basestring) and colType.isdigit() else colType if Backend.isDbms(DBMS.FIREBIRD): colType = FIREBIRD_TYPES.get(key, colType) elif Backend.isDbms(DBMS.INFORMIX): notNull = False if isinstance(key, int) and key > 255: key -= 256 notNull = True colType = INFORMIX_TYPES.get(key, colType) if notNull: colType = "%s NOT NULL" % colType column = safeSQLIdentificatorNaming(column) columns[column] = colType else: column = safeSQLIdentificatorNaming(column) columns[column] = None if columns: if conf.db in kb.data.cachedColumns: kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)][safeSQLIdentificatorNaming( tbl, True)] = columns else: table[safeSQLIdentificatorNaming(tbl, True)] = columns kb.data.cachedColumns[safeSQLIdentificatorNaming( conf.db)] = table if not kb.data.cachedColumns: warnMsg = "unable to retrieve column names for " warnMsg += ("table '%s' " % unsafeSQLIdentificatorNaming(unArrayizeValue(tblList)) ) if len(tblList) == 1 else "any table " warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( conf.db) logger.warn(warnMsg) if bruteForce is None: return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True) return kb.data.cachedColumns