sqlmap/plugins/generic/users.py

674 lines
28 KiB
Python
Raw Permalink Normal View History

2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2012-07-20 22:17:35 +04:00
"""
2022-01-03 13:30:34 +03:00
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
2012-07-20 22:17:35 +04:00
"""
import re
from lib.core.agent import agent
from lib.core.common import arrayizeValue
from lib.core.common import Backend
from lib.core.common import filterPairValues
from lib.core.common import getLimitRange
2012-10-25 00:59:46 +04:00
from lib.core.common import isAdminFromPrivileges
2012-07-20 22:17:35 +04:00
from lib.core.common import isInferenceAvailable
from lib.core.common import isNoneValue
2019-06-16 18:23:46 +03:00
from lib.core.common import isNullValue
2012-07-20 22:17:35 +04:00
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import parsePasswordHash
from lib.core.common import readInput
from lib.core.common import unArrayizeValue
2019-03-28 18:04:38 +03:00
from lib.core.compat import xrange
2019-05-03 14:20:15 +03:00
from lib.core.convert import encodeHex
2019-05-06 01:54:21 +03:00
from lib.core.convert import getUnicode
2012-07-20 22:17:35 +04:00
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.dicts import DB2_PRIVS
from lib.core.dicts import FIREBIRD_PRIVS
from lib.core.dicts import INFORMIX_PRIVS
2012-08-21 13:30:01 +04:00
from lib.core.dicts import MYSQL_PRIVS
from lib.core.dicts import PGSQL_PRIVS
2012-07-20 22:17:35 +04:00
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import FORK
2012-07-20 22:17:35 +04:00
from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapUserQuitException
2019-08-30 15:43:56 +03:00
from lib.core.settings import CURRENT_USER
from lib.core.settings import PLUS_ONE_DBMSES
2012-07-20 22:17:35 +04:00
from lib.core.threads import getCurrentThreadData
from lib.request import inject
from lib.utils.hash import attackCachedUsersPasswords
2012-12-04 20:04:32 +04:00
from lib.utils.hash import storeHashesToFile
2012-09-10 21:23:24 +04:00
from lib.utils.pivotdumptable import pivotDumpTable
2019-05-03 00:51:54 +03:00
from thirdparty.six.moves import zip as _zip
2012-07-20 22:17:35 +04:00
2019-05-29 17:42:04 +03:00
class Users(object):
2012-07-20 22:17:35 +04:00
"""
This class defines users' enumeration functionalities for plugins.
"""
def __init__(self):
kb.data.currentUser = ""
kb.data.isDba = None
kb.data.cachedUsers = []
kb.data.cachedUsersPasswords = {}
kb.data.cachedUsersPrivileges = {}
kb.data.cachedUsersRoles = {}
def getCurrentUser(self):
infoMsg = "fetching current user"
logger.info(infoMsg)
query = queries[Backend.getIdentifiedDbms()].current_user.query
if not kb.data.currentUser:
kb.data.currentUser = unArrayizeValue(inject.getValue(query))
return kb.data.currentUser
def isDba(self, user=None):
infoMsg = "testing if current user is DBA"
logger.info(infoMsg)
query = None
2012-07-20 22:17:35 +04:00
if Backend.isDbms(DBMS.MYSQL):
self.getCurrentUser()
2021-07-05 00:07:55 +03:00
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
kb.data.isDba = "root" in (kb.data.currentUser or "")
elif kb.data.currentUser:
query = queries[Backend.getIdentifiedDbms()].is_dba.query % kb.data.currentUser.split("@")[0]
2012-07-20 22:17:35 +04:00
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and user is not None:
query = queries[Backend.getIdentifiedDbms()].is_dba.query2 % user
else:
query = queries[Backend.getIdentifiedDbms()].is_dba.query
if query:
query = agent.forgeCaseStatement(query)
kb.data.isDba = inject.checkBooleanExpression(query) or False
2012-07-20 22:17:35 +04:00
2012-09-13 12:20:24 +04:00
return kb.data.isDba
2012-07-20 22:17:35 +04:00
def getUsers(self):
infoMsg = "fetching database users"
logger.info(infoMsg)
rootQuery = queries[Backend.getIdentifiedDbms()].users
condition = (Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")))
condition |= (Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema)
2012-12-05 13:45:17 +04:00
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
2021-07-05 00:07:55 +03:00
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
query = rootQuery.inband.query3
elif condition:
2012-07-20 22:17:35 +04:00
query = rootQuery.inband.query2
else:
query = rootQuery.inband.query
values = inject.getValue(query, blind=False, time=False)
2012-07-20 22:17:35 +04:00
if not isNoneValue(values):
2014-11-06 13:41:10 +03:00
kb.data.cachedUsers = []
for value in arrayizeValue(values):
2014-12-03 10:46:02 +03:00
value = unArrayizeValue(value)
if not isNoneValue(value):
kb.data.cachedUsers.append(value)
2012-07-20 22:17:35 +04:00
if not kb.data.cachedUsers and isInferenceAvailable() and not conf.direct:
infoMsg = "fetching number of database users"
logger.info(infoMsg)
2021-07-05 00:07:55 +03:00
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
query = rootQuery.blind.count3
elif condition:
2012-07-20 22:17:35 +04:00
query = rootQuery.blind.count2
else:
query = rootQuery.blind.count
2012-10-25 11:56:36 +04:00
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2012-07-20 22:17:35 +04:00
2014-08-20 01:56:04 +04:00
if count == 0:
return kb.data.cachedUsers
elif not isNumPosStrValue(count):
2012-07-20 22:17:35 +04:00
errMsg = "unable to retrieve the number of database users"
raise SqlmapNoneDataException(errMsg)
2012-07-20 22:17:35 +04:00
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
2012-07-20 22:17:35 +04:00
indexRange = getLimitRange(count, plusOne=plusOne)
for index in indexRange:
if Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MAXDB):
query = rootQuery.blind.query % (kb.data.cachedUsers[-1] if kb.data.cachedUsers else " ")
2021-07-05 00:07:55 +03:00
elif Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
query = rootQuery.blind.query3 % index
2012-07-20 22:17:35 +04:00
elif condition:
query = rootQuery.blind.query2 % index
else:
query = rootQuery.blind.query % index
user = unArrayizeValue(inject.getValue(query, union=False, error=False))
2012-07-20 22:17:35 +04:00
if user:
kb.data.cachedUsers.append(user)
if not kb.data.cachedUsers:
errMsg = "unable to retrieve the database users"
logger.error(errMsg)
2012-07-20 22:17:35 +04:00
return kb.data.cachedUsers
def getPasswordHashes(self):
infoMsg = "fetching database users password hashes"
rootQuery = queries[Backend.getIdentifiedDbms()].passwords
2019-08-30 15:43:56 +03:00
if conf.user == CURRENT_USER:
2012-07-20 22:17:35 +04:00
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:
2017-04-18 16:56:24 +03:00
users = conf.user.split(',')
2012-07-20 22:17:35 +04:00
if Backend.isDbms(DBMS.MYSQL):
for user in users:
2017-10-31 13:38:09 +03:00
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
2012-07-20 22:17:35 +04:00
if parsedUser:
users[users.index(user)] = parsedUser.groups()[0]
else:
users = []
users = [_ for _ in users if _]
2012-07-20 22:17:35 +04:00
2012-12-05 13:45:17 +04:00
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
2012-07-20 22:17:35 +04:00
if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")):
query = rootQuery.inband.query2
else:
query = rootQuery.inband.query
condition = rootQuery.inband.condition
if conf.user:
query += " WHERE "
query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users))
if Backend.isDbms(DBMS.SYBASE):
getCurrentThreadData().disableStdOut = True
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=False)
2012-07-20 22:17:35 +04:00
if retVal:
2019-05-03 00:51:54 +03:00
for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])):
2012-07-20 22:17:35 +04:00
if user not in kb.data.cachedUsersPasswords:
kb.data.cachedUsersPasswords[user] = [password]
else:
kb.data.cachedUsersPasswords[user].append(password)
getCurrentThreadData().disableStdOut = False
else:
values = inject.getValue(query, blind=False, time=False)
2012-07-20 22:17:35 +04:00
2019-06-16 18:23:46 +03:00
if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values):
values = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), blind=False, time=False)
2019-06-16 18:23:46 +03:00
elif Backend.isDbms(DBMS.MYSQL) and (isNoneValue(values) or all(len(value) == 2 and (isNullValue(value[1]) or isNoneValue(value[1])) for value in values)):
values = inject.getValue(query.replace("authentication_string", "password"), blind=False, time=False)
for user, password in filterPairValues(values):
2012-07-20 22:17:35 +04:00
if not user or user == " ":
continue
password = parsePasswordHash(password)
if user not in kb.data.cachedUsersPasswords:
kb.data.cachedUsersPasswords[user] = [password]
else:
kb.data.cachedUsersPasswords[user].append(password)
if not kb.data.cachedUsersPasswords and isInferenceAvailable() and not conf.direct:
fallback = False
2012-07-20 22:17:35 +04:00
if not len(users):
users = self.getUsers()
if Backend.isDbms(DBMS.MYSQL):
for user in users:
2017-10-31 13:38:09 +03:00
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
2012-07-20 22:17:35 +04:00
if parsedUser:
users[users.index(user)] = parsedUser.groups()[0]
if Backend.isDbms(DBMS.SYBASE):
getCurrentThreadData().disableStdOut = True
query = rootQuery.inband.query
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=True)
2012-07-20 22:17:35 +04:00
if retVal:
2019-05-03 00:51:54 +03:00
for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])):
2019-05-03 14:20:15 +03:00
password = "0x%s" % encodeHex(password, binary=False).upper()
2012-07-20 22:17:35 +04:00
if user not in kb.data.cachedUsersPasswords:
kb.data.cachedUsersPasswords[user] = [password]
else:
kb.data.cachedUsersPasswords[user].append(password)
getCurrentThreadData().disableStdOut = False
else:
retrievedUsers = set()
for user in users:
2013-06-01 15:44:27 +04:00
user = unArrayizeValue(user)
2012-07-20 22:17:35 +04:00
if user in retrievedUsers:
continue
2021-02-15 16:07:04 +03:00
if Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO):
2016-09-26 17:38:03 +03:00
count = 1
2012-07-20 22:17:35 +04:00
else:
2016-09-26 17:38:03 +03:00
infoMsg = "fetching number of password hashes "
infoMsg += "for user '%s'" % user
logger.info(infoMsg)
2012-10-25 11:56:36 +04:00
2016-09-26 17:38:03 +03:00
if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")):
query = rootQuery.blind.count2 % user
else:
query = rootQuery.blind.count % user
2012-07-20 22:17:35 +04:00
2016-09-26 17:38:03 +03:00
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2019-06-16 18:23:46 +03:00
if not isNumPosStrValue(count):
if Backend.isDbms(DBMS.MSSQL):
fallback = True
count = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
elif Backend.isDbms(DBMS.MYSQL):
fallback = True
count = inject.getValue(query.replace("authentication_string", "password"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2016-09-26 17:38:03 +03:00
if not isNumPosStrValue(count):
warnMsg = "unable to retrieve the number of password "
warnMsg += "hashes for user '%s'" % user
logger.warn(warnMsg)
continue
2012-07-20 22:17:35 +04:00
infoMsg = "fetching password hashes for user '%s'" % user
logger.info(infoMsg)
passwords = []
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
2012-07-20 22:17:35 +04:00
indexRange = getLimitRange(count, plusOne=plusOne)
for index in indexRange:
if Backend.isDbms(DBMS.MSSQL):
if Backend.isVersionWithin(("2005", "2008")):
query = rootQuery.blind.query2 % (user, index, user)
else:
query = rootQuery.blind.query % (user, index, user)
if fallback:
query = query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr")
2021-02-15 16:07:04 +03:00
elif Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO):
2016-09-26 17:38:03 +03:00
query = rootQuery.blind.query % (user,)
2018-11-19 11:44:13 +03:00
elif Backend.isDbms(DBMS.HSQLDB):
query = rootQuery.blind.query % (index, user)
2012-07-20 22:17:35 +04:00
else:
query = rootQuery.blind.query % (user, index)
2012-10-25 11:56:36 +04:00
2019-06-16 18:23:46 +03:00
if Backend.isDbms(DBMS.MYSQL):
if fallback:
query = query.replace("authentication_string", "password")
password = unArrayizeValue(inject.getValue(query, union=False, error=False))
2012-07-20 22:17:35 +04:00
password = parsePasswordHash(password)
2016-09-26 17:38:03 +03:00
2012-07-20 22:17:35 +04:00
passwords.append(password)
if passwords:
kb.data.cachedUsersPasswords[user] = passwords
else:
warnMsg = "unable to retrieve the password "
warnMsg += "hashes for user '%s'" % user
logger.warn(warnMsg)
retrievedUsers.add(user)
if not kb.data.cachedUsersPasswords:
errMsg = "unable to retrieve the password hashes for the "
2020-03-02 14:43:12 +03:00
errMsg += "database users"
logger.error(errMsg)
2012-07-20 22:17:35 +04:00
else:
for user in kb.data.cachedUsersPasswords:
kb.data.cachedUsersPasswords[user] = list(set(kb.data.cachedUsersPasswords[user]))
storeHashesToFile(kb.data.cachedUsersPasswords)
2012-12-04 20:04:32 +04:00
message = "do you want to perform a dictionary-based attack "
message += "against retrieved password hashes? [Y/n/q]"
2017-04-19 15:46:27 +03:00
choice = readInput(message, default='Y').upper()
2012-07-20 22:17:35 +04:00
2017-04-18 16:48:05 +03:00
if choice == 'N':
pass
2017-04-18 16:48:05 +03:00
elif choice == 'Q':
raise SqlmapUserQuitException
else:
attackCachedUsersPasswords()
2012-07-20 22:17:35 +04:00
return kb.data.cachedUsersPasswords
def getPrivileges(self, query2=False):
infoMsg = "fetching database users privileges"
rootQuery = queries[Backend.getIdentifiedDbms()].privileges
2019-08-30 15:43:56 +03:00
if conf.user == CURRENT_USER:
2012-07-20 22:17:35 +04:00
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:
2017-04-18 16:48:05 +03:00
users = conf.user.split(',')
2012-07-20 22:17:35 +04:00
if Backend.isDbms(DBMS.MYSQL):
for user in users:
2017-10-31 13:38:09 +03:00
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
2012-07-20 22:17:35 +04:00
if parsedUser:
users[users.index(user)] = parsedUser.groups()[0]
else:
users = []
users = [_ for _ in users if _]
2012-07-20 22:17:35 +04:00
# Set containing the list of DBMS administrators
areAdmins = set()
2013-01-14 14:24:45 +04:00
if not kb.data.cachedUsersPrivileges and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
2012-07-20 22:17:35 +04:00
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)
2012-07-20 22:17:35 +04:00
if not values and Backend.isDbms(DBMS.ORACLE) and not query2:
2019-08-30 15:43:56 +03:00
infoMsg = "trying with table 'USER_SYS_PRIVS'"
2012-07-20 22:17:35 +04:00
logger.info(infoMsg)
return self.getPrivileges(query2=True)
if not isNoneValue(values):
for value in values:
user = None
privileges = set()
2017-07-05 12:31:42 +03:00
for count in xrange(0, len(value or [])):
2012-07-20 22:17:35 +04:00
# The first column is always the username
if count == 0:
user = value[count]
# The other columns are the privileges
else:
privilege = value[count]
2013-10-16 13:25:26 +04:00
if privilege is None:
continue
2012-07-20 22:17:35 +04:00
# In PostgreSQL we get 1 if the privilege is
# True, 0 otherwise
if Backend.isDbms(DBMS.PGSQL) and getUnicode(privilege).isdigit():
2020-03-09 12:44:11 +03:00
if int(privilege) == 1 and count in PGSQL_PRIVS:
2012-08-21 13:30:01 +04:00
privileges.add(PGSQL_PRIVS[count])
2012-07-20 22:17:35 +04:00
# In MySQL >= 5.0 and Oracle we get the list
# of privileges as string
2020-02-03 13:33:19 +03:00
elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID):
2012-07-20 22:17:35 +04:00
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:
2019-08-30 15:43:56 +03:00
if privilege.upper() == 'Y':
2012-08-21 13:30:01 +04:00
privileges.add(MYSQL_PRIVS[count])
2012-07-20 22:17:35 +04:00
2013-01-21 19:46:48 +04:00
# In Firebird we get one letter for each privilege
elif Backend.isDbms(DBMS.FIREBIRD):
2017-05-29 11:57:27 +03:00
if privilege.strip() in FIREBIRD_PRIVS:
privileges.add(FIREBIRD_PRIVS[privilege.strip()])
2013-01-21 19:46:48 +04:00
2012-07-20 22:17:35 +04:00
# In DB2 we get Y or G if the privilege is
# True, N otherwise
elif Backend.isDbms(DBMS.DB2):
2017-04-18 16:56:24 +03:00
privs = privilege.split(',')
2012-07-20 22:17:35 +04:00
privilege = privs[0]
2014-12-18 17:13:44 +03:00
if len(privs) > 1:
privs = privs[1]
privs = list(privs.strip())
i = 1
for priv in privs:
2019-08-30 15:43:56 +03:00
if priv.upper() in ('Y', 'G'):
2014-12-18 17:13:44 +03:00
for position, db2Priv in DB2_PRIVS.items():
if position == i:
privilege += ", " + db2Priv
i += 1
2012-07-20 22:17:35 +04:00
privileges.add(privilege)
if user in kb.data.cachedUsersPrivileges:
2012-12-18 15:43:23 +04:00
kb.data.cachedUsersPrivileges[user] = list(privileges.union(kb.data.cachedUsersPrivileges[user]))
2012-07-20 22:17:35 +04:00
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:
2014-08-13 15:32:17 +04:00
conditionChar = "LIKE"
2012-07-20 22:17:35 +04:00
else:
conditionChar = "="
if not len(users):
users = self.getUsers()
if Backend.isDbms(DBMS.MYSQL):
for user in users:
2017-10-31 13:38:09 +03:00
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
2012-07-20 22:17:35 +04:00
if parsedUser:
users[users.index(user)] = parsedUser.groups()[0]
retrievedUsers = set()
for user in users:
2012-12-17 17:51:46 +04:00
outuser = user
2012-07-20 22:17:35 +04:00
if user in retrievedUsers:
continue
if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
user = "%%%s%%" % user
if Backend.isDbms(DBMS.INFORMIX):
count = 1
2012-07-20 22:17:35 +04:00
else:
infoMsg = "fetching number of privileges "
infoMsg += "for user '%s'" % outuser
logger.info(infoMsg)
2012-10-25 11:56:36 +04:00
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)
2012-07-20 22:17:35 +04:00
if not isNumPosStrValue(count):
if not retrievedUsers and Backend.isDbms(DBMS.ORACLE) and not query2:
2019-08-30 15:43:56 +03:00
infoMsg = "trying with table 'USER_SYS_PRIVS'"
logger.info(infoMsg)
2012-07-20 22:17:35 +04:00
return self.getPrivileges(query2=True)
2012-07-20 22:17:35 +04:00
warnMsg = "unable to retrieve the number of "
warnMsg += "privileges for user '%s'" % outuser
logger.warn(warnMsg)
continue
2012-07-20 22:17:35 +04:00
2012-12-17 17:51:46 +04:00
infoMsg = "fetching privileges for user '%s'" % outuser
2012-07-20 22:17:35 +04:00
logger.info(infoMsg)
privileges = set()
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
2012-07-20 22:17:35 +04:00
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,)
2012-07-20 22:17:35 +04:00
else:
query = rootQuery.blind.query % (user, index)
2013-10-16 13:25:26 +04:00
privilege = unArrayizeValue(inject.getValue(query, union=False, error=False))
2012-07-20 22:17:35 +04:00
2013-10-16 13:25:26 +04:00
if privilege is None:
continue
2012-07-20 22:17:35 +04:00
# In PostgreSQL we get 1 if the privilege is True,
# 0 otherwise
if Backend.isDbms(DBMS.PGSQL) and ", " in privilege:
2017-04-18 16:56:24 +03:00
privilege = privilege.replace(", ", ',')
privs = privilege.split(',')
2012-07-20 22:17:35 +04:00
i = 1
for priv in privs:
2020-03-09 12:44:11 +03:00
if priv.isdigit() and int(priv) == 1 and i in PGSQL_PRIVS:
privileges.add(PGSQL_PRIVS[i])
2012-07-20 22:17:35 +04:00
i += 1
# In MySQL >= 5.0 and Oracle we get the list
# of privileges as string
2020-02-03 13:33:19 +03:00
elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID):
2012-07-20 22:17:35 +04:00
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:
2017-04-18 16:56:24 +03:00
privilege = privilege.replace(", ", ',')
privs = privilege.split(',')
2012-07-20 22:17:35 +04:00
i = 1
for priv in privs:
2017-04-18 16:56:24 +03:00
if priv.upper() == 'Y':
2012-08-21 13:30:01 +04:00
for position, mysqlPriv in MYSQL_PRIVS.items():
2012-07-20 22:17:35 +04:00
if position == i:
privileges.add(mysqlPriv)
i += 1
# In Firebird we get one letter for each privilege
elif Backend.isDbms(DBMS.FIREBIRD):
2019-10-10 15:40:56 +03:00
if privilege.strip() in FIREBIRD_PRIVS:
privileges.add(FIREBIRD_PRIVS[privilege.strip()])
2012-07-20 22:17:35 +04:00
# In Informix we get one letter for the highest privilege
elif Backend.isDbms(DBMS.INFORMIX):
2020-09-11 17:28:10 +03:00
if privilege.strip() in INFORMIX_PRIVS:
privileges.add(INFORMIX_PRIVS[privilege.strip()])
2012-07-20 22:17:35 +04:00
# In DB2 we get Y or G if the privilege is
# True, N otherwise
elif Backend.isDbms(DBMS.DB2):
2017-04-18 16:56:24 +03:00
privs = privilege.split(',')
2012-07-20 22:17:35 +04:00
privilege = privs[0]
privs = privs[1]
privs = list(privs.strip())
i = 1
for priv in privs:
2017-04-18 16:56:24 +03:00
if priv.upper() in ('Y', 'G'):
2012-08-21 13:30:01 +04:00
for position, db2Priv in DB2_PRIVS.items():
2012-07-20 22:17:35 +04:00
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 "
2012-12-17 17:51:46 +04:00
warnMsg += "for user '%s'" % outuser
2012-07-20 22:17:35 +04:00
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)
2012-07-20 22:17:35 +04:00
2013-01-14 14:24:45 +04:00
for user, privileges in kb.data.cachedUsersPrivileges.items():
if isAdminFromPrivileges(privileges):
areAdmins.add(user)
2012-07-20 22:17:35 +04:00
return (kb.data.cachedUsersPrivileges, areAdmins)
def getRoles(self, query2=False):
warnMsg = "on %s the concept of roles does not " % Backend.getIdentifiedDbms()
warnMsg += "exist. sqlmap will enumerate privileges instead"
logger.warn(warnMsg)
return self.getPrivileges(query2)