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