1#!/usr/bin/env python 2 3""" 4Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) 5See the file 'LICENSE' for copying permission 6""" 7 8from lib.core.common import getLimitRange 9from lib.core.common import isAdminFromPrivileges 10from lib.core.common import isInferenceAvailable 11from lib.core.common import isNoneValue 12from lib.core.common import isNumPosStrValue 13from lib.core.common import isTechniqueAvailable 14from lib.core.compat import xrange 15from lib.core.data import conf 16from lib.core.data import kb 17from lib.core.data import logger 18from lib.core.data import queries 19from lib.core.enums import CHARSET_TYPE 20from lib.core.enums import DBMS 21from lib.core.enums import EXPECTED 22from lib.core.enums import PAYLOAD 23from lib.core.exception import SqlmapNoneDataException 24from lib.core.settings import CURRENT_USER 25from lib.request import inject 26from plugins.generic.enumeration import Enumeration as GenericEnumeration 27 28class Enumeration(GenericEnumeration): 29 def getRoles(self, query2=False): 30 infoMsg = "fetching database users roles" 31 32 rootQuery = queries[DBMS.ORACLE].roles 33 34 if conf.user == CURRENT_USER: 35 infoMsg += " for current user" 36 conf.user = self.getCurrentUser() 37 38 logger.info(infoMsg) 39 40 # Set containing the list of DBMS administrators 41 areAdmins = set() 42 43 if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: 44 if query2: 45 query = rootQuery.inband.query2 46 condition = rootQuery.inband.condition2 47 else: 48 query = rootQuery.inband.query 49 condition = rootQuery.inband.condition 50 51 if conf.user: 52 users = conf.user.split(',') 53 query += " WHERE " 54 query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users)) 55 56 values = inject.getValue(query, blind=False, time=False) 57 58 if not values and not query2: 59 infoMsg = "trying with table 'USER_ROLE_PRIVS'" 60 logger.info(infoMsg) 61 62 return self.getRoles(query2=True) 63 64 if not isNoneValue(values): 65 for value in values: 66 user = None 67 roles = set() 68 69 for count in xrange(0, len(value or [])): 70 # The first column is always the username 71 if count == 0: 72 user = value[count] 73 74 # The other columns are the roles 75 else: 76 role = value[count] 77 78 # In Oracle we get the list of roles as string 79 roles.add(role) 80 81 if user in kb.data.cachedUsersRoles: 82 kb.data.cachedUsersRoles[user] = list(roles.union(kb.data.cachedUsersRoles[user])) 83 else: 84 kb.data.cachedUsersRoles[user] = list(roles) 85 86 if not kb.data.cachedUsersRoles and isInferenceAvailable() and not conf.direct: 87 if conf.user: 88 users = conf.user.split(',') 89 else: 90 if not len(kb.data.cachedUsers): 91 users = self.getUsers() 92 else: 93 users = kb.data.cachedUsers 94 95 retrievedUsers = set() 96 97 for user in users: 98 unescapedUser = None 99 100 if user in retrievedUsers: 101 continue 102 103 infoMsg = "fetching number of roles " 104 infoMsg += "for user '%s'" % user 105 logger.info(infoMsg) 106 107 if unescapedUser: 108 queryUser = unescapedUser 109 else: 110 queryUser = user 111 112 if query2: 113 query = rootQuery.blind.count2 % queryUser 114 else: 115 query = rootQuery.blind.count % queryUser 116 count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) 117 118 if not isNumPosStrValue(count): 119 if count != 0 and not query2: 120 infoMsg = "trying with table 'USER_SYS_PRIVS'" 121 logger.info(infoMsg) 122 123 return self.getPrivileges(query2=True) 124 125 warnMsg = "unable to retrieve the number of " 126 warnMsg += "roles for user '%s'" % user 127 logger.warn(warnMsg) 128 continue 129 130 infoMsg = "fetching roles for user '%s'" % user 131 logger.info(infoMsg) 132 133 roles = set() 134 135 indexRange = getLimitRange(count, plusOne=True) 136 137 for index in indexRange: 138 if query2: 139 query = rootQuery.blind.query2 % (queryUser, index) 140 else: 141 query = rootQuery.blind.query % (queryUser, index) 142 role = inject.getValue(query, union=False, error=False) 143 144 # In Oracle we get the list of roles as string 145 roles.add(role) 146 147 if roles: 148 kb.data.cachedUsersRoles[user] = list(roles) 149 else: 150 warnMsg = "unable to retrieve the roles " 151 warnMsg += "for user '%s'" % user 152 logger.warn(warnMsg) 153 154 retrievedUsers.add(user) 155 156 if not kb.data.cachedUsersRoles: 157 errMsg = "unable to retrieve the roles " 158 errMsg += "for the database users" 159 raise SqlmapNoneDataException(errMsg) 160 161 for user, privileges in kb.data.cachedUsersRoles.items(): 162 if isAdminFromPrivileges(privileges): 163 areAdmins.add(user) 164 165 return kb.data.cachedUsersRoles, areAdmins 166