mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-25 17:09:02 +00:00
Major bug fix so that the users' privileges enumeration now works properly also on both MySQL < 5.0 and MySQL >= 5.0 also if the user has provided one or more users with -U option;
This commit is contained in:
@@ -67,30 +67,33 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression):
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
#unescaped = ""
|
||||
unescaped = "("
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
#unescaped = "("
|
||||
unescaped = ""
|
||||
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "CHAR(%d)" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += "+"
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "CHAR(%d)" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += "+"
|
||||
|
||||
unescaped += ")"
|
||||
expression = expression.replace(old, unescaped)
|
||||
#unescaped += ")"
|
||||
expression = expression.replace(old, unescaped)
|
||||
else:
|
||||
expression = "+".join("CHAR(%d)" % ord(c) for c in expression)
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@@ -66,28 +66,35 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression):
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
unescaped = ""
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
unescaped = ""
|
||||
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "%d" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += ","
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "%d" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += ","
|
||||
|
||||
expression = expression.replace(old, "CHAR(%s)" % unescaped)
|
||||
expression = expression.replace(old, "CHAR(%s)" % unescaped)
|
||||
else:
|
||||
unescaped = "CHAR("
|
||||
unescaped += ",".join("%d" % ord(c) for c in expression)
|
||||
unescaped += ")"
|
||||
|
||||
expression = unescaped
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@@ -59,30 +59,33 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression):
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
#unescaped = ""
|
||||
unescaped = "("
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
#unescaped = "("
|
||||
unescaped = ""
|
||||
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "CHR(%d)" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += "||"
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "CHR(%d)" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += "||"
|
||||
|
||||
unescaped += ")"
|
||||
expression = expression.replace(old, unescaped)
|
||||
#unescaped += ")"
|
||||
expression = expression.replace(old, unescaped)
|
||||
else:
|
||||
expression = "||".join("CHR(%d)" % ord(c) for c in expression)
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@@ -59,29 +59,33 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression):
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
while True:
|
||||
index = expression.find("'")
|
||||
if index == -1:
|
||||
break
|
||||
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
firstIndex = index + 1
|
||||
index = expression[firstIndex:].find("'")
|
||||
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
unescaped = "("
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
#unescaped = "("
|
||||
unescaped = ""
|
||||
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "CHR(%d)" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += "||"
|
||||
for i in range(firstIndex, lastIndex):
|
||||
unescaped += "CHR(%d)" % (ord(expression[i]))
|
||||
if i < lastIndex - 1:
|
||||
unescaped += "||"
|
||||
|
||||
unescaped += ")"
|
||||
expression = expression.replace(old, unescaped)
|
||||
#unescaped += ")"
|
||||
expression = expression.replace(old, unescaped)
|
||||
else:
|
||||
expression = "||".join("CHR(%d)" % ord(c) for c in expression)
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ from lib.core.exception import sqlmapNoneDataException
|
||||
from lib.core.exception import sqlmapUndefinedMethod
|
||||
from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||
from lib.core.shell import autoCompletion
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.request import inject
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
@@ -346,19 +347,19 @@ class Enumeration:
|
||||
if "," in conf.user:
|
||||
users = conf.user.split(",")
|
||||
query += " WHERE "
|
||||
# NOTE: we need this here only for MySQL 5.0 because
|
||||
# of a known issue explained in queries.xml
|
||||
# NOTE: I assume that the user provided is not in
|
||||
# MySQL >= 5.0 syntax 'user'@'host'
|
||||
if kb.dbms == "MySQL" and self.has_information_schema:
|
||||
likeUser = "%" + conf.user + "%"
|
||||
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)
|
||||
else:
|
||||
# NOTE: we need this here only for MySQL 5.0 because
|
||||
# of a known issue explained in queries.xml
|
||||
# NOTE: I assume that the user provided is not in
|
||||
# MySQL >= 5.0 syntax 'user'@'host'
|
||||
if kb.dbms == "MySQL" and self.has_information_schema:
|
||||
likeUser = "%" + conf.user + "%"
|
||||
query += " WHERE %s LIKE '%s'" % (condition, likeUser)
|
||||
queryUser = "%" + conf.user + "%"
|
||||
query += " WHERE %s LIKE '%s'" % (condition, queryUser)
|
||||
else:
|
||||
query += " WHERE %s = '%s'" % (condition, conf.user)
|
||||
|
||||
@@ -406,11 +407,25 @@ class Enumeration:
|
||||
self.cachedUsersPrivileges[user] = list(privileges)
|
||||
|
||||
if not self.cachedUsersPrivileges:
|
||||
conditionChar = "="
|
||||
|
||||
if conf.user:
|
||||
if "," in conf.user:
|
||||
if kb.dbms == "MySQL" and self.has_information_schema:
|
||||
conditionChar = " LIKE "
|
||||
|
||||
if "," in conf.user:
|
||||
users = set()
|
||||
for user in conf.user.split(","):
|
||||
users.add("%" + user + "%")
|
||||
else:
|
||||
users = [ "%" + conf.user + "%" ]
|
||||
|
||||
elif "," in conf.user:
|
||||
users = conf.user.split(",")
|
||||
|
||||
else:
|
||||
users = [conf.user]
|
||||
users = [ conf.user ]
|
||||
|
||||
else:
|
||||
if not len(self.cachedUsers):
|
||||
users = self.getUsers()
|
||||
@@ -420,11 +435,10 @@ class Enumeration:
|
||||
retrievedUsers = set()
|
||||
|
||||
for user in users:
|
||||
if kb.dbms == "MySQL":
|
||||
parsedUser = re.search("\047(.*?)\047@'", user)
|
||||
unescapedUser = None
|
||||
|
||||
if parsedUser:
|
||||
user = parsedUser.groups()[0].replace("'", "")
|
||||
if kb.dbms == "MySQL" and self.has_information_schema:
|
||||
unescapedUser = unescaper.unescape(user, quote=False)
|
||||
|
||||
if user in retrievedUsers:
|
||||
continue
|
||||
@@ -433,24 +447,26 @@ class Enumeration:
|
||||
logMsg += "for user '%s'" % user
|
||||
logger.info(logMsg)
|
||||
|
||||
if kb.dbms == "MySQL" and self.has_information_schema:
|
||||
likeUser = "%" + user + "%"
|
||||
if unescapedUser:
|
||||
queryUser = unescapedUser
|
||||
else:
|
||||
likeUser = user
|
||||
queryUser = user
|
||||
|
||||
if kb.dbms == "MySQL" and not self.has_information_schema:
|
||||
query = rootQuery["blind"]["count2"] % likeUser
|
||||
query = rootQuery["blind"]["count2"] % queryUser
|
||||
elif kb.dbms == "MySQL" and self.has_information_schema:
|
||||
query = rootQuery["blind"]["count"] % (conditionChar, queryUser)
|
||||
else:
|
||||
query = rootQuery["blind"]["count"] % likeUser
|
||||
query = rootQuery["blind"]["count"] % queryUser
|
||||
count = inject.getValue(query, inband=False)
|
||||
|
||||
if not len(count) or count == "0":
|
||||
warnMsg = "unable to retrieve the number of "
|
||||
warnMsg += "privileges for user '%s'" % likeUser
|
||||
warnMsg += "privileges for user '%s'" % user
|
||||
logger.warn(warnMsg)
|
||||
continue
|
||||
|
||||
logMsg = "fetching privileges for user '%s'" % likeUser
|
||||
logMsg = "fetching privileges for user '%s'" % user
|
||||
logger.info(logMsg)
|
||||
|
||||
privileges = set()
|
||||
@@ -458,13 +474,15 @@ class Enumeration:
|
||||
|
||||
for index in indexRange:
|
||||
if kb.dbms == "MySQL" and not self.has_information_schema:
|
||||
query = rootQuery["blind"]["query2"] % (likeUser, index)
|
||||
query = rootQuery["blind"]["query2"] % (queryUser, index)
|
||||
elif kb.dbms == "MySQL" and self.has_information_schema:
|
||||
query = rootQuery["blind"]["query"] % (conditionChar, queryUser, index)
|
||||
else:
|
||||
query = rootQuery["blind"]["query"] % (likeUser, index)
|
||||
query = rootQuery["blind"]["query"] % (queryUser, index)
|
||||
privilege = inject.getValue(query, inband=False)
|
||||
|
||||
# In PostgreSQL we return 1 if the privilege
|
||||
# if True, otherwise 0
|
||||
# In PostgreSQL we get 1 if the privilege is True,
|
||||
# 0 otherwise
|
||||
if kb.dbms == "PostgreSQL" and ", " in privilege:
|
||||
privilege = privilege.replace(", ", ",")
|
||||
privs = privilege.split(",")
|
||||
@@ -501,6 +519,12 @@ class Enumeration:
|
||||
if self.__isAdminFromPrivileges(privileges):
|
||||
areAdmins.add(user)
|
||||
|
||||
# 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 kb.dbms == "MySQL" and not self.has_information_schema:
|
||||
break
|
||||
|
||||
if privileges:
|
||||
self.cachedUsersPrivileges[user] = list(privileges)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user