def getPrivileges(self, query2=False): infoMsg = "fetching database users privileges" rootQuery = queries[Backend.getIdentifiedDbms()].privileges if conf.user == "CU": infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.user = conf.user.upper() if conf.user: users = conf.user.split(',') if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search("[\047]*(.*?)[\047]*\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] else: users = [] users = filter(None, users) # Set containing the list of DBMS administrators areAdmins = set() if not kb.data.cachedUsersPrivileges and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: query += " WHERE " if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query += " OR ".join("%s LIKE '%%%s%%'" % (condition, user) for user in sorted(users)) else: query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) values = inject.getValue(query, blind=False, time=False) if not values and Backend.isDbms(DBMS.ORACLE) and not query2: infoMsg = "trying with table USER_SYS_PRIVS" logger.info(infoMsg) return self.getPrivileges(query2=True) if not isNoneValue(values): for value in values: user = None privileges = set() for count in xrange(0, len(value or [])): # The first column is always the username if count == 0: user = value[count] # The other columns are the privileges else: privilege = value[count] if privilege is None: continue # In PostgreSQL we get 1 if the privilege is # True, 0 otherwise if Backend.isDbms(DBMS.PGSQL) and getUnicode(privilege).isdigit(): if int(privilege) == 1: privileges.add(PGSQL_PRIVS[count]) # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: if privilege.upper() == "Y": privileges.add(MYSQL_PRIVS[count]) # In Firebird we get one letter for each privilege elif Backend.isDbms(DBMS.FIREBIRD): if privilege.strip() in FIREBIRD_PRIVS: privileges.add(FIREBIRD_PRIVS[privilege.strip()]) # In DB2 we get Y or G if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.DB2): privs = privilege.split(',') privilege = privs[0] if len(privs) > 1: privs = privs[1] privs = list(privs.strip()) i = 1 for priv in privs: if priv.upper() in ("Y", "G"): for position, db2Priv in DB2_PRIVS.items(): if position == i: privilege += ", " + db2Priv i += 1 privileges.add(privilege) if user in kb.data.cachedUsersPrivileges: kb.data.cachedUsersPrivileges[user] = list(privileges.union(kb.data.cachedUsersPrivileges[user])) else: kb.data.cachedUsersPrivileges[user] = list(privileges) if not kb.data.cachedUsersPrivileges and isInferenceAvailable() and not conf.direct: if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: conditionChar = "LIKE" else: conditionChar = "=" if not len(users): users = self.getUsers() if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search("[\047]*(.*?)[\047]*\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] retrievedUsers = set() for user in users: outuser = user if user in retrievedUsers: continue if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: user = "******" % user if Backend.isDbms(DBMS.INFORMIX): count = 1 else: infoMsg = "fetching number of privileges " infoMsg += "for user '%s'" % outuser logger.info(infoMsg) if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.count2 % user elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query = rootQuery.blind.count % (conditionChar, user) elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.blind.count2 % user else: query = rootQuery.blind.count % user count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if not retrievedUsers and Backend.isDbms(DBMS.ORACLE) 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 += "privileges for user '%s'" % outuser logger.warn(warnMsg) continue infoMsg = "fetching privileges for user '%s'" % outuser logger.info(infoMsg) privileges = set() plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.query2 % (user, index) elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query = rootQuery.blind.query % (conditionChar, user, index) elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.blind.query2 % (user, index) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (index, user) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (user,) else: query = rootQuery.blind.query % (user, index) privilege = unArrayizeValue(inject.getValue(query, union=False, error=False)) if privilege is None: continue # In PostgreSQL we get 1 if the privilege is True, # 0 otherwise if Backend.isDbms(DBMS.PGSQL) 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 PGSQL_PRIVS.items(): if position == i: privileges.add(pgsqlPriv) i += 1 # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: privilege = privilege.replace(", ", ',') privs = privilege.split(',') i = 1 for priv in privs: if priv.upper() == 'Y': for position, mysqlPriv in MYSQL_PRIVS.items(): if position == i: privileges.add(mysqlPriv) i += 1 # In Firebird we get one letter for each privilege elif Backend.isDbms(DBMS.FIREBIRD): privileges.add(FIREBIRD_PRIVS[privilege.strip()]) # In Informix we get one letter for the highest privilege elif Backend.isDbms(DBMS.INFORMIX): privileges.add(INFORMIX_PRIVS[privilege.strip()]) # In DB2 we get Y or G if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.DB2): privs = privilege.split(',') privilege = privs[0] privs = privs[1] privs = list(privs.strip()) i = 1 for priv in privs: if priv.upper() in ('Y', 'G'): for position, db2Priv in DB2_PRIVS.items(): if position == i: privilege += ", " + db2Priv i += 1 privileges.add(privilege) # 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 Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: break if privileges: kb.data.cachedUsersPrivileges[user] = list(privileges) else: warnMsg = "unable to retrieve the privileges " warnMsg += "for user '%s'" % outuser logger.warn(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersPrivileges: errMsg = "unable to retrieve the privileges " errMsg += "for the database users" raise SqlmapNoneDataException(errMsg) for user, privileges in kb.data.cachedUsersPrivileges.items(): if isAdminFromPrivileges(privileges): areAdmins.add(user) return (kb.data.cachedUsersPrivileges, areAdmins)
def getPrivileges(self, query2=False): infoMsg = "fetching database users privileges" rootQuery = queries[Backend.getIdentifiedDbms()].privileges if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() logger.info(infoMsg) if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): conf.user = conf.user.upper() if conf.user: users = conf.user.split(',') if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] else: users = [] users = [_ for _ in users if _] # Set containing the list of DBMS administrators areAdmins = set() if not kb.data.cachedUsersPrivileges and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 else: query = rootQuery.inband.query condition = rootQuery.inband.condition if conf.user: query += " WHERE " if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query += " OR ".join("%s LIKE '%%%s%%'" % (condition, user) for user in sorted(users)) else: query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) values = inject.getValue(query, blind=False, time=False) if not values and Backend.isDbms(DBMS.ORACLE) and not query2: infoMsg = "trying with table 'USER_SYS_PRIVS'" logger.info(infoMsg) return self.getPrivileges(query2=True) if not isNoneValue(values): for value in values: user = None privileges = set() for count in xrange(0, len(value or [])): # The first column is always the username if count == 0: user = value[count] # The other columns are the privileges else: privilege = value[count] if privilege is None: continue # In PostgreSQL we get 1 if the privilege is # True, 0 otherwise if Backend.isDbms(DBMS.PGSQL) and getUnicode(privilege).isdigit(): if int(privilege) == 1: privileges.add(PGSQL_PRIVS[count]) # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: if privilege.upper() == 'Y': privileges.add(MYSQL_PRIVS[count]) # In Firebird we get one letter for each privilege elif Backend.isDbms(DBMS.FIREBIRD): if privilege.strip() in FIREBIRD_PRIVS: privileges.add(FIREBIRD_PRIVS[privilege.strip()]) # In DB2 we get Y or G if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.DB2): privs = privilege.split(',') privilege = privs[0] if len(privs) > 1: privs = privs[1] privs = list(privs.strip()) i = 1 for priv in privs: if priv.upper() in ('Y', 'G'): for position, db2Priv in DB2_PRIVS.items(): if position == i: privilege += ", " + db2Priv i += 1 privileges.add(privilege) if user in kb.data.cachedUsersPrivileges: kb.data.cachedUsersPrivileges[user] = list(privileges.union(kb.data.cachedUsersPrivileges[user])) else: kb.data.cachedUsersPrivileges[user] = list(privileges) if not kb.data.cachedUsersPrivileges and isInferenceAvailable() and not conf.direct: if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: conditionChar = "LIKE" else: conditionChar = "=" if not len(users): users = self.getUsers() if Backend.isDbms(DBMS.MYSQL): for user in users: parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user) if parsedUser: users[users.index(user)] = parsedUser.groups()[0] retrievedUsers = set() for user in users: outuser = user if user in retrievedUsers: continue if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: user = "******" % user if Backend.isDbms(DBMS.INFORMIX): count = 1 else: infoMsg = "fetching number of privileges " infoMsg += "for user '%s'" % outuser logger.info(infoMsg) if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.count2 % user elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query = rootQuery.blind.count % (conditionChar, user) elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.blind.count2 % user else: query = rootQuery.blind.count % user count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(count): if not retrievedUsers and Backend.isDbms(DBMS.ORACLE) 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 += "privileges for user '%s'" % outuser logger.warn(warnMsg) continue infoMsg = "fetching privileges for user '%s'" % outuser logger.info(infoMsg) privileges = set() plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: query = rootQuery.blind.query2 % (user, index) elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema: query = rootQuery.blind.query % (conditionChar, user, index) elif Backend.isDbms(DBMS.ORACLE) and query2: query = rootQuery.blind.query2 % (user, index) elif Backend.isDbms(DBMS.FIREBIRD): query = rootQuery.blind.query % (index, user) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (user,) else: query = rootQuery.blind.query % (user, index) privilege = unArrayizeValue(inject.getValue(query, union=False, error=False)) if privilege is None: continue # In PostgreSQL we get 1 if the privilege is True, # 0 otherwise if Backend.isDbms(DBMS.PGSQL) 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 PGSQL_PRIVS.items(): if position == i: privileges.add(pgsqlPriv) i += 1 # In MySQL >= 5.0 and Oracle we get the list # of privileges as string elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: privilege = privilege.replace(", ", ',') privs = privilege.split(',') i = 1 for priv in privs: if priv.upper() == 'Y': for position, mysqlPriv in MYSQL_PRIVS.items(): if position == i: privileges.add(mysqlPriv) i += 1 # In Firebird we get one letter for each privilege elif Backend.isDbms(DBMS.FIREBIRD): if privilege.strip() in FIREBIRD_PRIVS: privileges.add(FIREBIRD_PRIVS[privilege.strip()]) # In Informix we get one letter for the highest privilege elif Backend.isDbms(DBMS.INFORMIX): privileges.add(INFORMIX_PRIVS[privilege.strip()]) # In DB2 we get Y or G if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.DB2): privs = privilege.split(',') privilege = privs[0] privs = privs[1] privs = list(privs.strip()) i = 1 for priv in privs: if priv.upper() in ('Y', 'G'): for position, db2Priv in DB2_PRIVS.items(): if position == i: privilege += ", " + db2Priv i += 1 privileges.add(privilege) # 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 Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: break if privileges: kb.data.cachedUsersPrivileges[user] = list(privileges) else: warnMsg = "unable to retrieve the privileges " warnMsg += "for user '%s'" % outuser logger.warn(warnMsg) retrievedUsers.add(user) if not kb.data.cachedUsersPrivileges: errMsg = "unable to retrieve the privileges " errMsg += "for the database users" raise SqlmapNoneDataException(errMsg) for user, privileges in kb.data.cachedUsersPrivileges.items(): if isAdminFromPrivileges(privileges): areAdmins.add(user) return (kb.data.cachedUsersPrivileges, areAdmins)