mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-31 11:59:04 +00:00
Added support for --roles (for Oracle ROLE_PRIVS). Enhanced Oracle --privileges to fall-back to USER_SYS_PRIVS if DBA_SYS_PRIVS is not accessible (so session user is not DBA) - Fixes ticket #180.
Minor enhancement to Firebird to determine if a DB user is a DBA. Minor code refactoring.
This commit is contained in:
@@ -22,7 +22,12 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
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.exception import sqlmapNoneDataException
|
||||
from lib.request import inject
|
||||
|
||||
from plugins.generic.enumeration import Enumeration as GenericEnumeration
|
||||
|
||||
@@ -30,6 +35,145 @@ class Enumeration(GenericEnumeration):
|
||||
def __init__(self):
|
||||
GenericEnumeration.__init__(self, "Oracle")
|
||||
|
||||
def getRoles(self, query2=False):
|
||||
infoMsg = "fetching database users roles"
|
||||
|
||||
rootQuery = queries[kb.dbms].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 kb.unionPosition:
|
||||
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:
|
||||
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, expected="int", charsetType=2)
|
||||
|
||||
if not count.isdigit() or not len(count) or count == "0":
|
||||
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)
|
||||
|
||||
# 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 getDbs(self):
|
||||
warnMsg = "on Oracle it is not possible to enumerate databases"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
@@ -60,6 +60,7 @@ class Enumeration:
|
||||
kb.data.cachedUsers = []
|
||||
kb.data.cachedUsersPasswords = {}
|
||||
kb.data.cachedUsersPrivileges = {}
|
||||
kb.data.cachedUsersRoles = {}
|
||||
kb.data.cachedDbs = []
|
||||
kb.data.cachedTables = {}
|
||||
kb.data.cachedColumns = {}
|
||||
@@ -327,9 +328,14 @@ class Enumeration:
|
||||
# that the user is DBA
|
||||
dbaCondition |= ( kb.dbms == "MySQL" and not kb.data.has_information_schema and "super_priv" in privileges )
|
||||
|
||||
# In Firebird there is no specific privilege that means
|
||||
# that the user is DBA
|
||||
# TODO: confirm
|
||||
dbaCondition |= ( kb.dbms == "Firebird" and "SELECT" in privileges and "INSERT" in privileges and "UPDATE" in privileges and "DELETE" in privileges and "REFERENCES" in privileges and "EXECUTE" in privileges )
|
||||
|
||||
return dbaCondition
|
||||
|
||||
def getPrivileges(self):
|
||||
def getPrivileges(self, query2=False):
|
||||
infoMsg = "fetching database users privileges"
|
||||
|
||||
rootQuery = queries[kb.dbms].privileges
|
||||
@@ -377,7 +383,7 @@ class Enumeration:
|
||||
( 2, "super" ),
|
||||
( 3, "catupd" ),
|
||||
)
|
||||
|
||||
|
||||
firebirdPrivs = {
|
||||
"S": "SELECT",
|
||||
"I": "INSERT",
|
||||
@@ -391,38 +397,32 @@ class Enumeration:
|
||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||
query = rootQuery["inband"]["query2"]
|
||||
condition = rootQuery["inband"]["condition2"]
|
||||
elif kb.dbms == "Oracle" and query2:
|
||||
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 kb.data.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)
|
||||
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 kb.data.has_information_schema:
|
||||
queryUser = "%" + conf.user + "%"
|
||||
query += " OR ".join("%s LIKE '%s'" % (condition, "%" + user + "%") for user in users)
|
||||
else:
|
||||
if kb.dbms == "MySQL":
|
||||
parsedUser = re.search("[\047]*(.*?)[\047]*\@", conf.user)
|
||||
|
||||
if parsedUser:
|
||||
conf.user = parsedUser.groups()[0]
|
||||
|
||||
# NOTE: I assume that the user provided is not in
|
||||
# MySQL >= 5.0 syntax 'user'@'host'
|
||||
if kb.dbms == "MySQL" and kb.data.has_information_schema:
|
||||
queryUser = "%" + conf.user + "%"
|
||||
query += " WHERE %s LIKE '%s'" % (condition, queryUser)
|
||||
else:
|
||||
query += " WHERE %s = '%s'" % (condition, conf.user)
|
||||
query += " OR ".join("%s = '%s'" % (condition, user) for user in users)
|
||||
|
||||
values = inject.getValue(query, blind=False)
|
||||
|
||||
if not values and kb.dbms == "Oracle" and not query2:
|
||||
infoMsg = "trying with table USER_SYS_PRIVS"
|
||||
logger.info(infoMsg)
|
||||
|
||||
return self.getPrivileges(query2=True)
|
||||
|
||||
if values:
|
||||
for value in values:
|
||||
user = None
|
||||
@@ -482,13 +482,8 @@ class Enumeration:
|
||||
conf.user = parsedUser.groups()[0]
|
||||
|
||||
users = [ "%" + conf.user + "%" ]
|
||||
|
||||
elif "," in conf.user:
|
||||
users = conf.user.split(",")
|
||||
|
||||
else:
|
||||
users = [ conf.user ]
|
||||
|
||||
users = conf.user.split(",")
|
||||
else:
|
||||
if not len(kb.data.cachedUsers):
|
||||
users = self.getUsers()
|
||||
@@ -519,11 +514,19 @@ class Enumeration:
|
||||
query = rootQuery["blind"]["count2"] % queryUser
|
||||
elif kb.dbms == "MySQL" and kb.data.has_information_schema:
|
||||
query = rootQuery["blind"]["count"] % (conditionChar, queryUser)
|
||||
elif kb.dbms == "Oracle" and query2:
|
||||
query = rootQuery["blind"]["count2"] % queryUser
|
||||
else:
|
||||
query = rootQuery["blind"]["count"] % queryUser
|
||||
count = inject.getValue(query, inband=False, expected="int", charsetType=2)
|
||||
|
||||
if not count.isdigit() or not len(count) or count == "0":
|
||||
if not count.isdigit() and kb.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'" % user
|
||||
logger.warn(warnMsg)
|
||||
@@ -545,6 +548,8 @@ class Enumeration:
|
||||
query = rootQuery["blind"]["query2"] % (queryUser, index)
|
||||
elif kb.dbms == "MySQL" and kb.data.has_information_schema:
|
||||
query = rootQuery["blind"]["query"] % (conditionChar, queryUser, index)
|
||||
elif kb.dbms == "Oracle" and query2:
|
||||
query = rootQuery["blind"]["query2"] % (queryUser, index)
|
||||
elif kb.dbms == "Firebird":
|
||||
query = rootQuery["blind"]["query"] % (index, queryUser)
|
||||
else:
|
||||
@@ -585,6 +590,8 @@ class Enumeration:
|
||||
privileges.add(mysqlPriv)
|
||||
|
||||
i += 1
|
||||
|
||||
# In Firebird we get one letter for each privilege
|
||||
elif kb.dbms == "Firebird":
|
||||
privileges.add(firebirdPrivs[privilege.strip()])
|
||||
|
||||
@@ -613,6 +620,11 @@ class Enumeration:
|
||||
|
||||
return ( kb.data.cachedUsersPrivileges, areAdmins )
|
||||
|
||||
def getRoles(self, query2=False):
|
||||
warnMsg = "on %s the concept of roles does not " % kb.dbms
|
||||
warnMsg += "exist. sqlmap will enumerate privileges instead"
|
||||
self.getPrivileges(query2)
|
||||
|
||||
def getDbs(self):
|
||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||
warnMsg = "information_schema not available, "
|
||||
|
||||
Reference in New Issue
Block a user