@ -52,69 +52,100 @@ from thirdparty.six.moves import zip as _zip
class Users ( object ) :
"""
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 = { }
# 初始化用户相关的数据存储
kb . data . currentUser = " " # 当前用户
kb . data . isDba = None # 是否是DBA
kb . data . cachedUsers = [ ] # 缓存的用户列表
kb . data . cachedUsersPasswords = { } # 缓存的用户密码哈希
kb . data . cachedUsersPrivileges = { } # 缓存的用户权限
kb . data . cachedUsersRoles = { } # 缓存的用户角色
def getCurrentUser ( self ) :
"""
Retrieves the current database user .
获取当前数据库用户
"""
infoMsg = " fetching current user "
logger . info ( infoMsg )
# 获取当前用户的SQL查询语句
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 ) :
"""
Tests if the current or specified user is a DBA .
测试当前或指定用户是否是DBA ( 数据库管理员 ) 。
Args :
user ( str , optional ) : 要测试的用户 , 默认为None , 表示测试当前用户
Returns :
bool : 是否是DBA
"""
infoMsg = " testing if current user is DBA "
logger . info ( infoMsg )
query = None
# 根据不同的数据库类型, 构造不同的SQL查询语句
if Backend . isDbms ( DBMS . MYSQL ) :
self . getCurrentUser ( )
self . getCurrentUser ( ) # 先获取当前用户
if Backend . isDbms ( DBMS . MYSQL ) and Backend . isFork ( FORK . DRIZZLE ) :
kb . data . isDba = " root " in ( kb . data . currentUser or " " )
kb . data . isDba = " root " in ( kb . data . currentUser or " " ) # Drizzle数据库, 通过用户名判断是否为root用户
elif kb . data . currentUser :
query = queries [ Backend . getIdentifiedDbms ( ) ] . is_dba . query % kb . data . currentUser . split ( " @ " ) [ 0 ]
query = queries [ Backend . getIdentifiedDbms ( ) ] . is_dba . query % kb . data . currentUser . split ( " @ " ) [ 0 ] # 构建查询语句, 判断是否为MySQL的DBA
elif Backend . getIdentifiedDbms ( ) in ( DBMS . MSSQL , DBMS . SYBASE ) and user is not None :
query = queries [ Backend . getIdentifiedDbms ( ) ] . is_dba . query2 % user
query = queries [ Backend . getIdentifiedDbms ( ) ] . is_dba . query2 % user # 构建查询语句, 判断是否为SQL Server或Sybase的DBA
else :
query = queries [ Backend . getIdentifiedDbms ( ) ] . is_dba . query
query = queries [ Backend . getIdentifiedDbms ( ) ] . is_dba . query # 构建查询语句, 判断是否为其他数据库的DBA
# 执行查询
if query :
query = agent . forgeCaseStatement ( query )
kb . data . isDba = inject . checkBooleanExpression ( query ) or False
query = agent . forgeCaseStatement ( query ) # 注入时, 构造Case语句
kb . data . isDba = inject . checkBooleanExpression ( query ) or False # 执行查询, 并判断是否为DBA
return kb . data . isDba
def getUsers ( self ) :
"""
Retrieves database users .
获取数据库用户 。
Returns :
list : 用户列表
"""
infoMsg = " fetching database users "
logger . info ( infoMsg )
# 获取查询用户表的SQL查询语句
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 )
# 优先使用union, error, query技术进行查询, 否则使用盲注技术
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
if Backend . isDbms ( DBMS . MYSQL ) and Backend . isFork ( FORK . DRIZZLE ) :
query = rootQuery . inband . query3
query = rootQuery . inband . query3 # Drizzle数据库的查询语句
elif condition :
query = rootQuery . inband . query2
query = rootQuery . inband . query2 # 条件判断下的查询语句
else :
query = rootQuery . inband . query
query = rootQuery . inband . query # 通用查询语句
values = inject . getValue ( query , blind = False , time = False )
values = inject . getValue ( query , blind = False , time = False ) # 执行查询语句,获取用户列表
# 处理返回的用户列表
if not isNoneValue ( values ) :
kb . data . cachedUsers = [ ]
for value in arrayizeValue ( values ) :
@ -122,18 +153,19 @@ class Users(object):
if not isNoneValue ( value ) :
kb . data . cachedUsers . append ( value )
# 如果没有使用union, error, query技术获取到用户, 则使用盲注技术进行获取
if not kb . data . cachedUsers and isInferenceAvailable ( ) and not conf . direct :
infoMsg = " fetching number of database users "
logger . info ( infoMsg )
if Backend . isDbms ( DBMS . MYSQL ) and Backend . isFork ( FORK . DRIZZLE ) :
query = rootQuery . blind . count3
query = rootQuery . blind . count3 # Drizzle数据库的查询语句
elif condition :
query = rootQuery . blind . count2
query = rootQuery . blind . count2 # 条件判断下的查询语句
else :
query = rootQuery . blind . count
query = rootQuery . blind . count # 通用查询语句
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS ) # 获取用户数量
if count == 0 :
return kb . data . cachedUsers
@ -142,8 +174,9 @@ class Users(object):
raise SqlmapNoneDataException ( errMsg )
plusOne = Backend . getIdentifiedDbms ( ) in PLUS_ONE_DBMSES
indexRange = getLimitRange ( count , plusOne = plusOne )
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 " " )
@ -166,8 +199,16 @@ class Users(object):
return kb . data . cachedUsers
def getPasswordHashes ( self ) :
"""
Retrieves password hashes of database users .
获取数据库用户的密码哈希值 。
Returns :
dict : 用户名和密码哈希的字典
"""
infoMsg = " fetching database users password hashes "
# 获取查询密码哈希的SQL查询语句
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . passwords
if conf . user == CURRENT_USER :
@ -177,7 +218,7 @@ class Users(object):
logger . info ( infoMsg )
if conf . user and Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
conf . user = conf . user . upper ( )
conf . user = conf . user . upper ( ) # Oracle和DB2数据库的用户名为大写
if conf . user :
users = conf . user . split ( ' , ' )
@ -187,28 +228,31 @@ class Users(object):
parsedUser = re . search ( r " [ ' \" ]?(.*?)[ ' \" ]? \ @ " , user )
if parsedUser :
users [ users . index ( user ) ] = parsedUser . groups ( ) [ 0 ]
users [ users . index ( user ) ] = parsedUser . groups ( ) [ 0 ] # 处理MySQL的用户名格式, 去掉引号和@后面的部分
else :
users = [ ]
users = [ _ for _ in users if _ ]
# 优先使用union, error, query技术进行查询, 否则使用盲注技术
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
if Backend . isDbms ( DBMS . MSSQL ) and Backend . isVersionWithin ( ( " 2005 " , " 2008 " ) ) :
query = rootQuery . inband . query2
query = rootQuery . inband . query2 # SQL Server 2005和2008的查询语句
else :
query = rootQuery . inband . query
query = rootQuery . inband . query # 通用查询语句
condition = rootQuery . inband . condition
condition = rootQuery . inband . condition # 查询条件
# 如果指定了用户,则加入查询条件
if conf . user :
query + = " WHERE "
query + = " OR " . join ( " %s = ' %s ' " % ( condition , user ) for user in sorted ( users ) )
# 处理Sybase数据库的特殊情况
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 )
retVal = pivotDumpTable ( " ( %s ) AS %s " % ( query , kb . aliasName ) , [ ' %s .name ' % kb . aliasName , ' %s .password ' % kb . aliasName ] , blind = False ) # 使用pivotDumpTable函数获取用户名和密码哈希
if retVal :
for user , password in filterPairValues ( _zip ( retVal [ 0 ] [ " %s .name " % kb . aliasName ] , retVal [ 0 ] [ " %s .password " % kb . aliasName ] ) ) :
@ -219,13 +263,14 @@ class Users(object):
getCurrentThreadData ( ) . disableStdOut = False
else :
values = inject . getValue ( query , blind = False , time = False )
values = inject . getValue ( query , blind = False , time = False ) # 执行查询,获取用户名和密码哈希
if Backend . isDbms ( DBMS . MSSQL ) and isNoneValue ( values ) :
values = inject . getValue ( query . replace ( " master.dbo.fn_varbintohexstr " , " sys.fn_sqlvarbasetostr " ) , blind = False , time = False )
values = inject . getValue ( query . replace ( " master.dbo.fn_varbintohexstr " , " sys.fn_sqlvarbasetostr " ) , blind = False , time = False ) # SQL Server的特殊情况, 替换函数
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 )
values = inject . getValue ( query . replace ( " authentication_string " , " password " ) , blind = False , time = False ) # MySQL的特殊情况, 替换字段
# 处理返回的用户名和密码哈希
for user , password in filterPairValues ( values ) :
if not user or user == " " :
continue
@ -237,19 +282,21 @@ class Users(object):
else :
kb . data . cachedUsersPasswords [ user ] . append ( password )
# 如果没有使用union, error, query技术获取到密码哈希, 则使用盲注技术进行获取
if not kb . data . cachedUsersPasswords and isInferenceAvailable ( ) and not conf . direct :
fallback = False
if not len ( users ) :
users = self . getUsers ( )
users = self . getUsers ( ) # 先获取用户列表
if Backend . isDbms ( DBMS . MYSQL ) :
for user in users :
parsedUser = re . search ( r " [ ' \" ]?(.*?)[ ' \" ]? \ @ " , user )
if parsedUser :
users [ users . index ( user ) ] = parsedUser . groups ( ) [ 0 ]
users [ users . index ( user ) ] = parsedUser . groups ( ) [ 0 ] # 处理MySQL的用户名格式, 去掉引号和@后面的部分
# 处理Sybase数据库的特殊情况
if Backend . isDbms ( DBMS . SYBASE ) :
getCurrentThreadData ( ) . disableStdOut = True
@ -268,8 +315,9 @@ class Users(object):
getCurrentThreadData ( ) . disableStdOut = False
else :
retrievedUsers = set ( )
retrievedUsers = set ( ) # 已获取密码哈希的用户
# 循环盲注查询密码哈希
for user in users :
user = unArrayizeValue ( user )
@ -277,26 +325,26 @@ class Users(object):
continue
if Backend . getIdentifiedDbms ( ) in ( DBMS . INFORMIX , DBMS . VIRTUOSO ) :
count = 1
count = 1 # Informix和Virtuoso数据库的特殊情况, 直接查询密码哈希
else :
infoMsg = " fetching number of password hashes "
infoMsg + = " for user ' %s ' " % user
logger . info ( infoMsg )
if Backend . isDbms ( DBMS . MSSQL ) and Backend . isVersionWithin ( ( " 2005 " , " 2008 " ) ) :
query = rootQuery . blind . count2 % user
query = rootQuery . blind . count2 % user # SQL Server 2005和2008的查询语句
else :
query = rootQuery . blind . count % user
query = rootQuery . blind . count % user # 通用查询语句
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS ) # 获取密码哈希数量
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 )
count = inject . getValue ( query . replace ( " master.dbo.fn_varbintohexstr " , " sys.fn_sqlvarbasetostr " ) , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS ) # SQL Server的特殊情况, 替换函数
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 )
count = inject . getValue ( query . replace ( " authentication_string " , " password " ) , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS ) # MySQL的特殊情况, 替换字段
if not isNumPosStrValue ( count ) :
warnMsg = " unable to retrieve the number of password "
@ -310,33 +358,34 @@ class Users(object):
passwords = [ ]
plusOne = Backend . getIdentifiedDbms ( ) in PLUS_ONE_DBMSES
indexRange = getLimitRange ( count , plusOne = plusOne )
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 )
query = rootQuery . blind . query2 % ( user , index , user ) # SQL Server 2005和2008的查询语句
else :
query = rootQuery . blind . query % ( user , index , user )
query = rootQuery . blind . query % ( user , index , user ) # 通用查询语句
if fallback :
query = query . replace ( " master.dbo.fn_varbintohexstr " , " sys.fn_sqlvarbasetostr " )
query = query . replace ( " master.dbo.fn_varbintohexstr " , " sys.fn_sqlvarbasetostr " ) # SQL Server的特殊情况, 替换函数
elif Backend . getIdentifiedDbms ( ) in ( DBMS . INFORMIX , DBMS . VIRTUOSO ) :
query = rootQuery . blind . query % ( user , )
query = rootQuery . blind . query % ( user , ) # Informix和Virtuoso数据库的特殊情况
elif Backend . isDbms ( DBMS . HSQLDB ) :
query = rootQuery . blind . query % ( index , user )
query = rootQuery . blind . query % ( index , user ) # HSQLDB数据库的特殊情况
else :
query = rootQuery . blind . query % ( user , index )
query = rootQuery . blind . query % ( user , index ) # 通用查询语句
if Backend . isDbms ( DBMS . MYSQL ) :
if fallback :
query = query . replace ( " authentication_string " , " password " )
query = query . replace ( " authentication_string " , " password " ) # MySQL的特殊情况, 替换字段
password = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
password = parsePasswordHash ( password )
password = parsePasswordHash ( password ) # 解析密码哈希
passwords . append ( password )
@ -355,26 +404,37 @@ class Users(object):
logger . error ( errMsg )
else :
for user in kb . data . cachedUsersPasswords :
kb . data . cachedUsersPasswords [ user ] = list ( set ( kb . data . cachedUsersPasswords [ user ] ) )
kb . data . cachedUsersPasswords [ user ] = list ( set ( kb . data . cachedUsersPasswords [ user ] ) ) # 去重密码哈希
storeHashesToFile ( kb . data . cachedUsersPasswords )
storeHashesToFile ( kb . data . cachedUsersPasswords ) # 保存密码哈希到文件
message = " do you want to perform a dictionary-based attack "
message + = " against retrieved password hashes? [Y/n/q] "
choice = readInput ( message , default = ' Y ' ) . upper ( )
choice = readInput ( message , default = ' Y ' ) . upper ( ) # 提示是否进行字典攻击
if choice == ' N ' :
pass
elif choice == ' Q ' :
raise SqlmapUserQuitException
else :
attackCachedUsersPasswords ( )
attackCachedUsersPasswords ( ) # 进行字典攻击
return kb . data . cachedUsersPasswords
def getPrivileges ( self , query2 = False ) :
"""
Retrieves privileges of database users .
获取数据库用户的权限
Args :
query2 ( bool , optional ) : 是否使用第二种查询方式 , 默认为False
Returns :
tuple : 用户名和权限的字典 , 以及DBA用户的集合
"""
infoMsg = " fetching database users privileges "
# 获取查询权限的SQL查询语句
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . privileges
if conf . user == CURRENT_USER :
@ -401,36 +461,38 @@ class Users(object):
users = [ _ for _ in users if _ ]
# Set containing the list of DBMS administrators
areAdmins = set ( )
areAdmins = set ( ) # 存储DBA用户的集合
if not kb . data . cachedUsersPrivileges and any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
if Backend . isDbms ( DBMS . MYSQL ) and not kb . data . has_information_schema :
query = rootQuery . inband . query2
condition = rootQuery . inband . condition2
query = rootQuery . inband . query2 # MySQL 5.0以下版本的查询语句
condition = rootQuery . inband . condition2 # MySQL 5.0以下版本的查询条件
elif Backend . isDbms ( DBMS . ORACLE ) and query2 :
query = rootQuery . inband . query2
condition = rootQuery . inband . condition2
query = rootQuery . inband . query2 # Oracle的第二种查询方式
condition = rootQuery . inband . condition2 # Oracle的第二种查询条件
else :
query = rootQuery . inband . query
condition = rootQuery . inband . condition
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 ) )
query + = " OR " . join ( " %s LIKE ' %% %s %% ' " % ( condition , user ) for user in sorted ( users ) ) # MySQL 5.0以上版本的查询条件
else :
query + = " OR " . join ( " %s = ' %s ' " % ( condition , user ) for user in sorted ( users ) )
query + = " OR " . join ( " %s = ' %s ' " % ( condition , user ) for user in sorted ( users ) ) # 通用查询条件
values = inject . getValue ( query , blind = False , time = False )
values = inject . getValue ( query , blind = False , time = False ) # 执行查询语句,获取权限信息
if not values and Backend . isDbms ( DBMS . ORACLE ) and not query2 :
infoMsg = " trying with table ' USER_SYS_PRIVS ' "
logger . info ( infoMsg )
return self . getPrivileges ( query2 = True )
return self . getPrivileges ( query2 = True ) # 如果没有获取到权限信息,尝试使用第二种查询方式
if not isNoneValue ( values ) :
# 处理返回的权限信息
for value in values :
user = None
privileges = set ( )
@ -438,7 +500,7 @@ class Users(object):
for count in xrange ( 0 , len ( value or [ ] ) ) :
# The first column is always the username
if count == 0 :
user = value [ count ]
user = value [ count ] # 获取用户名
# The other columns are the privileges
else :
@ -451,23 +513,23 @@ class Users(object):
# True, 0 otherwise
if Backend . isDbms ( DBMS . PGSQL ) and getUnicode ( privilege ) . isdigit ( ) :
if int ( privilege ) == 1 and count in PGSQL_PRIVS :
privileges . add ( PGSQL_PRIVS [ count ] )
privileges . add ( PGSQL_PRIVS [ count ] ) # PostgreSQL的权限处理
# In MySQL >= 5.0 and Oracle we get the list
# of privileges as string
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 ) :
privileges . add ( privilege )
privileges . add ( privilege ) # MySQL 5.0以上版本和Oracle的权限处理
# 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 :
if privilege . upper ( ) == ' Y ' :
privileges . add ( MYSQL_PRIVS [ count ] )
privileges . add ( MYSQL_PRIVS [ count ] ) # MySQL 5.0以下版本的权限处理
# In Firebird we get one letter for each privilege
elif Backend . isDbms ( DBMS . FIREBIRD ) :
if privilege . strip ( ) in FIREBIRD_PRIVS :
privileges . add ( FIREBIRD_PRIVS [ privilege . strip ( ) ] )
privileges . add ( FIREBIRD_PRIVS [ privilege . strip ( ) ] ) # Firebird的权限处理
# In DB2 we get Y or G if the privilege is
# True, N otherwise
@ -487,21 +549,21 @@ class Users(object):
i + = 1
privileges . add ( privilege )
privileges . add ( privilege ) # DB2的权限处理
if user in kb . data . cachedUsersPrivileges :
kb . data . cachedUsersPrivileges [ user ] = list ( privileges . union ( kb . data . cachedUsersPrivileges [ user ] ) )
kb . data . cachedUsersPrivileges [ user ] = list ( privileges . union ( kb . data . cachedUsersPrivileges [ user ] ) ) # 合并权限
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 :
conditionChar = " LIKE "
conditionChar = " LIKE " # MySQL 5.0以上版本的模糊查询
else :
conditionChar = " = "
conditionChar = " = " # 通用查询
if not len ( users ) :
users = self . getUsers ( )
users = self . getUsers ( ) # 获取用户列表
if Backend . isDbms ( DBMS . MYSQL ) :
for user in users :
@ -510,33 +572,34 @@ class Users(object):
if parsedUser :
users [ users . index ( user ) ] = parsedUser . groups ( ) [ 0 ]
retrievedUsers = set ( )
retrievedUsers = set ( ) # 已获取权限的用户
# 循环盲注查询权限
for user in users :
outuser = user
if user in retrievedUsers :
continue
if Backend . isDbms ( DBMS . MYSQL ) and kb . data . has_information_schema :
user = " %% %s %% " % user
user = " %% %s %% " % user # MySQL 5.0以上版本的模糊查询
if Backend . isDbms ( DBMS . INFORMIX ) :
count = 1
count = 1 # Informix数据库的特殊情况, 直接查询权限
else :
infoMsg = " fetching number of privileges "
infoMsg + = " for user ' %s ' " % outuser
logger . info ( infoMsg )
if Backend . isDbms ( DBMS . MYSQL ) and not kb . data . has_information_schema :
query = rootQuery . blind . count2 % user
query = rootQuery . blind . count2 % user # MySQL 5.0以下版本的查询语句
elif Backend . isDbms ( DBMS . MYSQL ) and kb . data . has_information_schema :
query = rootQuery . blind . count % ( conditionChar , user )
query = rootQuery . blind . count % ( conditionChar , user ) # MySQL 5.0以上版本的查询语句
elif Backend . isDbms ( DBMS . ORACLE ) and query2 :
query = rootQuery . blind . count2 % user
query = rootQuery . blind . count2 % user # Oracle的第二种查询方式
else :
query = rootQuery . blind . count % user
query = rootQuery . blind . count % user # 通用查询语句
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS ) # 获取权限数量
if not isNumPosStrValue ( count ) :
if not retrievedUsers and Backend . isDbms ( DBMS . ORACLE ) and not query2 :
@ -556,21 +619,22 @@ class Users(object):
privileges = set ( )
plusOne = Backend . getIdentifiedDbms ( ) in PLUS_ONE_DBMSES
indexRange = getLimitRange ( count , plusOne = plusOne )
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 )
query = rootQuery . blind . query2 % ( user , index ) # MySQL 5.0以下版本的查询语句
elif Backend . isDbms ( DBMS . MYSQL ) and kb . data . has_information_schema :
query = rootQuery . blind . query % ( conditionChar , user , index )
query = rootQuery . blind . query % ( conditionChar , user , index ) # MySQL 5.0以上版本的查询语句
elif Backend . isDbms ( DBMS . ORACLE ) and query2 :
query = rootQuery . blind . query2 % ( user , index )
query = rootQuery . blind . query2 % ( user , index ) # Oracle的第二种查询方式
elif Backend . isDbms ( DBMS . FIREBIRD ) :
query = rootQuery . blind . query % ( index , user )
query = rootQuery . blind . query % ( index , user ) # Firebird数据库的查询语句
elif Backend . isDbms ( DBMS . INFORMIX ) :
query = rootQuery . blind . query % ( user , )
query = rootQuery . blind . query % ( user , ) # Informix数据库的查询语句
else :
query = rootQuery . blind . query % ( user , index )
query = rootQuery . blind . query % ( user , index ) # 通用查询语句
privilege = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
@ -586,14 +650,14 @@ class Users(object):
for priv in privs :
if priv . isdigit ( ) and int ( priv ) == 1 and i in PGSQL_PRIVS :
privileges . add ( PGSQL_PRIVS [ i ] )
privileges . add ( PGSQL_PRIVS [ i ] ) # PostgreSQL的权限处理
i + = 1
# In MySQL >= 5.0 and Oracle we get the list
# of privileges as string
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 ) :
privileges . add ( privilege )
privileges . add ( privilege ) # MySQL 5.0以上版本和Oracle的权限处理
# In MySQL < 5.0 we get Y if the privilege is
# True, N otherwise
@ -606,19 +670,19 @@ class Users(object):
if priv . upper ( ) == ' Y ' :
for position , mysqlPriv in MYSQL_PRIVS . items ( ) :
if position == i :
privileges . add ( mysqlPriv )
privileges . add ( mysqlPriv ) # MySQL 5.0以下版本的权限处理
i + = 1
# In Firebird we get one letter for each privilege
elif Backend . isDbms ( DBMS . FIREBIRD ) :
if privilege . strip ( ) in FIREBIRD_PRIVS :
privileges . add ( FIREBIRD_PRIVS [ privilege . strip ( ) ] )
privileges . add ( FIREBIRD_PRIVS [ privilege . strip ( ) ] ) # Firebird的权限处理
# In Informix we get one letter for the highest privilege
elif Backend . isDbms ( DBMS . INFORMIX ) :
if privilege . strip ( ) in INFORMIX_PRIVS :
privileges . add ( INFORMIX_PRIVS [ privilege . strip ( ) ] )
privileges . add ( INFORMIX_PRIVS [ privilege . strip ( ) ] ) # Informix的权限处理
# In DB2 we get Y or G if the privilege is
# True, N otherwise
@ -633,7 +697,7 @@ class Users(object):
if priv . upper ( ) in ( ' Y ' , ' G ' ) :
for position , db2Priv in DB2_PRIVS . items ( ) :
if position == i :
privilege + = " , " + db2Priv
privilege + = " , " + db2Priv # DB2的权限处理
i + = 1
@ -661,13 +725,6 @@ class Users(object):
for user , privileges in kb . data . cachedUsersPrivileges . items ( ) :
if isAdminFromPrivileges ( privileges ) :
areAdmins . add ( user )
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 . warning ( warnMsg )
areAdmins . add ( user ) # 判断是否为DBA
return self . getPrivileges ( query2 )
return ( kb . data . cachedUsersPrivileges )