@ -5,45 +5,50 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file ' LICENSE ' for copying permission
See the file ' LICENSE ' for copying permission
"""
"""
import re
# 导入必要的模块
import re # 导入正则表达式模块,用于进行模式匹配
from lib . core . agent import agent
from lib . core . common import arrayizeValue
from lib . core . agent import agent # 导入 agent 模块,用于执行 SQL 注入
from lib . core . common import getLimitRange
from lib . core . common import arrayizeValue # 导入 arrayizeValue 函数,用于将值转换为列表
from lib . core . common import isInferenceAvailable
from lib . core . common import getLimitRange # 导入 getLimitRange 函数,用于生成限制范围
from lib . core . common import isNoneValue
from lib . core . common import isInferenceAvailable # 导入 isInferenceAvailable 函数,用于检查是否可以使用推断注入
from lib . core . common import isNumPosStrValue
from lib . core . common import isNoneValue # 导入 isNoneValue 函数,用于检查值是否为 None
from lib . core . common import isTechniqueAvailable
from lib . core . common import isNumPosStrValue # 导入 isNumPosStrValue 函数,用于检查值是否为正数字字符串
from lib . core . common import safeSQLIdentificatorNaming
from lib . core . common import isTechniqueAvailable # 导入 isTechniqueAvailable 函数,用于检查指定的注入技术是否可用
from lib . core . common import safeStringFormat
from lib . core . common import safeSQLIdentificatorNaming # 导入 safeSQLIdentificatorNaming 函数,用于安全地命名 SQL 标识符
from lib . core . common import singleTimeLogMessage
from lib . core . common import safeStringFormat # 导入 safeStringFormat 函数,用于安全地格式化字符串
from lib . core . common import unArrayizeValue
from lib . core . common import singleTimeLogMessage # 导入 singleTimeLogMessage 函数,用于只输出一次的日志消息
from lib . core . common import unsafeSQLIdentificatorNaming
from lib . core . common import unArrayizeValue # 导入 unArrayizeValue 函数,用于从列表中提取值
from lib . core . compat import xrange
from lib . core . common import unsafeSQLIdentificatorNaming # 导入 unsafeSQLIdentificatorNaming 函数,用于不安全地命名 SQL 标识符
from lib . core . data import conf
from lib . core . compat import xrange # 导入 xrange 函数,用于兼容 Python 2 和 3 的循环
from lib . core . data import kb
from lib . core . data import conf # 导入 conf 对象,用于访问全局配置信息
from lib . core . data import logger
from lib . core . data import kb # 导入 kb 对象,用于访问全局知识库
from lib . core . data import queries
from lib . core . data import logger # 导入 logger 对象,用于输出日志
from lib . core . enums import CHARSET_TYPE
from lib . core . data import queries # 导入 queries 对象,用于获取预定义的 SQL 查询语句
from lib . core . enums import DBMS
from lib . core . enums import CHARSET_TYPE # 导入 CHARSET_TYPE 枚举,定义字符集类型
from lib . core . enums import EXPECTED
from lib . core . enums import DBMS # 导入 DBMS 枚举,定义数据库管理系统类型
from lib . core . enums import PAYLOAD
from lib . core . enums import EXPECTED # 导入 EXPECTED 枚举,定义期望的返回值类型
from lib . core . exception import SqlmapNoneDataException
from lib . core . enums import PAYLOAD # 导入 PAYLOAD 枚举,定义注入类型
from lib . core . settings import CURRENT_DB
from lib . core . exception import SqlmapNoneDataException # 导入 SqlmapNoneDataException 异常类,用于表示没有数据
from lib . request import inject
from lib . core . settings import CURRENT_DB # 导入 CURRENT_DB 常量,表示当前数据库
from plugins . generic . enumeration import Enumeration as GenericEnumeration
from lib . request import inject # 导入 inject 函数,用于执行 SQL 注入请求
from thirdparty import six
from plugins . generic . enumeration import Enumeration as GenericEnumeration # 导入 GenericEnumeration 类,作为当前类的父类
from thirdparty import six # 导入 six 模块,用于兼容 Python 2 和 3
# 定义 Enumeration 类,继承自 GenericEnumeration
class Enumeration ( GenericEnumeration ) :
class Enumeration ( GenericEnumeration ) :
# 定义 getPrivileges 方法,用于获取数据库用户的权限
def getPrivileges ( self , * args , * * kwargs ) :
def getPrivileges ( self , * args , * * kwargs ) :
# 输出警告信息,说明在 Microsoft SQL Server 上无法获取用户权限,只会检查是否是 DBA
warnMsg = " on Microsoft SQL Server it is not possible to fetch "
warnMsg = " on Microsoft SQL Server it is not possible to fetch "
warnMsg + = " database users privileges, sqlmap will check whether "
warnMsg + = " database users privileges, sqlmap will check whether "
warnMsg + = " or not the database users are database administrators "
warnMsg + = " or not the database users are database administrators "
logger . warning ( warnMsg )
logger . warning ( warnMsg )
users = [ ]
users = [ ] # 初始化用户列表
areAdmins = set ( )
areAdmins = set ( ) # 初始化管理员集合
# 如果配置中指定了用户,则使用该用户,否则获取所有用户
if conf . user :
if conf . user :
users = [ conf . user ]
users = [ conf . user ]
elif not len ( kb . data . cachedUsers ) :
elif not len ( kb . data . cachedUsers ) :
@ -51,91 +56,114 @@ class Enumeration(GenericEnumeration):
else :
else :
users = kb . data . cachedUsers
users = kb . data . cachedUsers
# 遍历用户列表
for user in users :
for user in users :
user = unArrayizeValue ( user )
user = unArrayizeValue ( user ) # 从列表中提取用户
if user is None :
if user is None : # 如果用户为 None, 则跳过
continue
continue
isDba = self . isDba ( user )
isDba = self . isDba ( user ) # 检查用户是否为 DBA
if isDba is True :
if isDba is True : # 如果是 DBA, 则添加到管理员集合
areAdmins . add ( user )
areAdmins . add ( user )
kb . data . cachedUsersPrivileges [ user ] = None
kb . data . cachedUsersPrivileges [ user ] = None # 设置用户的权限信息为 None
# 返回用户的权限信息和管理员集合
return ( kb . data . cachedUsersPrivileges , areAdmins )
return ( kb . data . cachedUsersPrivileges , areAdmins )
# 定义 getTables 方法,用于获取数据库表
def getTables ( self ) :
def getTables ( self ) :
# 如果知识库中已缓存表信息,则直接返回
if len ( kb . data . cachedTables ) > 0 :
if len ( kb . data . cachedTables ) > 0 :
return kb . data . cachedTables
return kb . data . cachedTables
self . forceDbmsEnum ( )
self . forceDbmsEnum ( ) # 强制执行 DBMS 枚举
# 如果配置中指定了当前数据库,则获取当前数据库
if conf . db == CURRENT_DB :
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
conf . db = self . getCurrentDb ( )
# 如果配置中指定了数据库,则分割数据库字符串,否则获取所有数据库
if conf . db :
if conf . db :
dbs = conf . db . split ( ' , ' )
dbs = conf . db . split ( ' , ' )
else :
else :
dbs = self . getDbs ( )
dbs = self . getDbs ( )
# 对每个数据库名进行安全命名
for db in dbs :
for db in dbs :
dbs [ dbs . index ( db ) ] = safeSQLIdentificatorNaming ( db )
dbs [ dbs . index ( db ) ] = safeSQLIdentificatorNaming ( db )
# 移除空字符串的数据库
dbs = [ _ for _ in dbs if _ ]
dbs = [ _ for _ in dbs if _ ]
# 输出获取表信息的提示信息
infoMsg = " fetching tables for database "
infoMsg = " fetching tables for database "
infoMsg + = " %s : %s " % ( " s " if len ( dbs ) > 1 else " " , " , " . join ( db if isinstance ( db , six . string_types ) else db [ 0 ] for db in sorted ( dbs ) ) )
infoMsg + = " %s : %s " % ( " s " if len ( dbs ) > 1 else " " , " , " . join ( db if isinstance ( db , six . string_types ) else db [ 0 ] for db in sorted ( dbs ) ) )
logger . info ( infoMsg )
logger . info ( infoMsg )
# 获取 SQL Server 的表查询语句
rootQuery = queries [ DBMS . MSSQL ] . tables
rootQuery = queries [ DBMS . MSSQL ] . tables
# 检查是否可以使用 UNION、ERROR、QUERY 注入技术或直接连接
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
# 遍历数据库列表
for db in dbs :
for db in dbs :
# 如果配置中排除了系统数据库,则跳过
if conf . excludeSysDbs and db in self . excludeDbsList :
if conf . excludeSysDbs and db in self . excludeDbsList :
infoMsg = " skipping system database ' %s ' " % db
infoMsg = " skipping system database ' %s ' " % db
singleTimeLogMessage ( infoMsg )
singleTimeLogMessage ( infoMsg )
continue
continue
# 如果配置中指定了排除的数据库,则跳过
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
infoMsg = " skipping database ' %s ' " % db
infoMsg = " skipping database ' %s ' " % db
singleTimeLogMessage ( infoMsg )
singleTimeLogMessage ( infoMsg )
continue
continue
# 尝试使用不同的查询语句获取表信息
for query in ( rootQuery . inband . query , rootQuery . inband . query2 , rootQuery . inband . query3 ) :
for query in ( rootQuery . inband . query , rootQuery . inband . query2 , rootQuery . inband . query3 ) :
query = query . replace ( " %s " , db )
query = query . replace ( " %s " , db )
value = inject . getValue ( query , blind = False , time = False )
value = inject . getValue ( query , blind = False , time = False ) # 执行注入并获取结果
if not isNoneValue ( value ) :
if not isNoneValue ( value ) : # 如果结果不为 None, 则跳出循环
break
break
# 如果获取到了表信息,则进行处理
if not isNoneValue ( value ) :
if not isNoneValue ( value ) :
value = [ _ for _ in arrayizeValue ( value ) if _ ]
value = [ _ for _ in arrayizeValue ( value ) if _ ] # 将结果转换为列表
value = [ safeSQLIdentificatorNaming ( unArrayizeValue ( _ ) , True ) for _ in value ]
value = [ safeSQLIdentificatorNaming ( unArrayizeValue ( _ ) , True ) for _ in value ] # 安全命名表名
kb . data . cachedTables [ db ] = value
kb . data . cachedTables [ db ] = value # 将表信息缓存到知识库
# 如果没有获取到表信息,并且可以使用推断注入,则使用推断注入获取表信息
if not kb . data . cachedTables and isInferenceAvailable ( ) and not conf . direct :
if not kb . data . cachedTables and isInferenceAvailable ( ) and not conf . direct :
# 遍历数据库列表
for db in dbs :
for db in dbs :
# 如果配置中排除了系统数据库,则跳过
if conf . excludeSysDbs and db in self . excludeDbsList :
if conf . excludeSysDbs and db in self . excludeDbsList :
infoMsg = " skipping system database ' %s ' " % db
infoMsg = " skipping system database ' %s ' " % db
singleTimeLogMessage ( infoMsg )
singleTimeLogMessage ( infoMsg )
continue
continue
# 如果配置中指定了排除的数据库,则跳过
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
infoMsg = " skipping database ' %s ' " % db
infoMsg = " skipping database ' %s ' " % db
singleTimeLogMessage ( infoMsg )
singleTimeLogMessage ( infoMsg )
continue
continue
# 输出获取表数量的提示信息
infoMsg = " fetching number of tables for "
infoMsg = " fetching number of tables for "
infoMsg + = " database ' %s ' " % db
infoMsg + = " database ' %s ' " % db
logger . info ( infoMsg )
logger . info ( infoMsg )
# 尝试使用不同的查询语句获取表数量
for query in ( rootQuery . blind . count , rootQuery . blind . count2 , rootQuery . blind . count3 ) :
for query in ( rootQuery . blind . count , rootQuery . blind . count2 , rootQuery . blind . count3 ) :
_ = query . replace ( " %s " , db )
_ = query . replace ( " %s " , db )
count = inject . getValue ( _ , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
count = inject . getValue ( _ , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS ) # 执行推断注入并获取结果
if not isNoneValue ( count ) :
if not isNoneValue ( count ) : # 如果结果不为 None, 则跳出循环
break
break
# 如果没有获取到有效的表数量,则跳过
if not isNumPosStrValue ( count ) :
if not isNumPosStrValue ( count ) :
if count != 0 :
if count != 0 :
warnMsg = " unable to retrieve the number of "
warnMsg = " unable to retrieve the number of "
@ -143,17 +171,18 @@ class Enumeration(GenericEnumeration):
logger . warning ( warnMsg )
logger . warning ( warnMsg )
continue
continue
tables = [ ]
tables = [ ] # 初始化表列表
# 遍历表索引,获取每个表名
for index in xrange ( int ( count ) ) :
for index in xrange ( int ( count ) ) :
_ = safeStringFormat ( ( rootQuery . blind . query if query == rootQuery . blind . count else rootQuery . blind . query2 if query == rootQuery . blind . count2 else rootQuery . blind . query3 ) . replace ( " %s " , db ) , index )
_ = safeStringFormat ( ( rootQuery . blind . query if query == rootQuery . blind . count else rootQuery . blind . query2 if query == rootQuery . blind . count2 else rootQuery . blind . query3 ) . replace ( " %s " , db ) , index )
table = inject . getValue ( _ , union = False , error = False ) # 执行推断注入并获取结果
table = inject . getValue ( _ , union = False , error = False )
if not isNoneValue ( table ) : # 如果结果不为 None, 则添加到表列表
if not isNoneValue ( table ) :
kb . hintValue = table
kb . hintValue = table
table = safeSQLIdentificatorNaming ( table , True )
table = safeSQLIdentificatorNaming ( table , True ) # 安全命名表名
tables . append ( table )
tables . append ( table )
# 如果获取到了表信息,则进行缓存,否则输出警告信息
if tables :
if tables :
kb . data . cachedTables [ db ] = tables
kb . data . cachedTables [ db ] = tables
else :
else :
@ -161,25 +190,31 @@ class Enumeration(GenericEnumeration):
warnMsg + = " for database ' %s ' " % db
warnMsg + = " for database ' %s ' " % db
logger . warning ( warnMsg )
logger . warning ( warnMsg )
# 如果没有获取到表信息,并且没有指定搜索,则抛出异常
if not kb . data . cachedTables and not conf . search :
if not kb . data . cachedTables and not conf . search :
errMsg = " unable to retrieve the tables for any database "
errMsg = " unable to retrieve the tables for any database "
raise SqlmapNoneDataException ( errMsg )
raise SqlmapNoneDataException ( errMsg )
else :
else :
# 对缓存的表名进行排序
for db , tables in kb . data . cachedTables . items ( ) :
for db , tables in kb . data . cachedTables . items ( ) :
kb . data . cachedTables [ db ] = sorted ( tables ) if tables else tables
kb . data . cachedTables [ db ] = sorted ( tables ) if tables else tables
# 返回缓存的表信息
return kb . data . cachedTables
return kb . data . cachedTables
# 定义 searchTable 方法,用于搜索指定的表
def searchTable ( self ) :
def searchTable ( self ) :
foundTbls = { }
foundTbls = { } # 初始化找到的表字典
tblList = conf . tbl . split ( ' , ' )
tblList = conf . tbl . split ( ' , ' ) # 获取要搜索的表列表
rootQuery = queries [ DBMS . MSSQL ] . search_table
rootQuery = queries [ DBMS . MSSQL ] . search_table # 获取 SQL Server 的表搜索查询语句
tblCond = rootQuery . inband . condition
tblCond = rootQuery . inband . condition # 获取表搜索条件
tblConsider , tblCondParam = self . likeOrExact ( " table " )
tblConsider , tblCondParam = self . likeOrExact ( " table " ) # 获取表搜索的方式 (LIKE 或 EXACT)
# 如果配置中指定了当前数据库,则获取当前数据库
if conf . db == CURRENT_DB :
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
conf . db = self . getCurrentDb ( )
# 如果配置中指定了数据库,则分割数据库字符串,否则获取所有数据库
if conf . db :
if conf . db :
enumDbs = conf . db . split ( ' , ' )
enumDbs = conf . db . split ( ' , ' )
elif not len ( kb . data . cachedDbs ) :
elif not len ( kb . data . cachedDbs ) :
@ -187,40 +222,48 @@ class Enumeration(GenericEnumeration):
else :
else :
enumDbs = kb . data . cachedDbs
enumDbs = kb . data . cachedDbs
# 初始化每个数据库的表搜索结果
for db in enumDbs :
for db in enumDbs :
db = safeSQLIdentificatorNaming ( db )
db = safeSQLIdentificatorNaming ( db )
foundTbls [ db ] = [ ]
foundTbls [ db ] = [ ]
# 遍历要搜索的表列表
for tbl in tblList :
for tbl in tblList :
tbl = safeSQLIdentificatorNaming ( tbl , True )
tbl = safeSQLIdentificatorNaming ( tbl , True ) # 安全命名表名
# 输出搜索表信息的提示信息
infoMsg = " searching table "
infoMsg = " searching table "
if tblConsider == " 1 " :
if tblConsider == " 1 " :
infoMsg + = " s LIKE "
infoMsg + = " s LIKE "
infoMsg + = " ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
infoMsg + = " ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
logger . info ( infoMsg )
logger . info ( infoMsg )
# 构建表搜索查询条件
tblQuery = " %s %s " % ( tblCond , tblCondParam )
tblQuery = " %s %s " % ( tblCond , tblCondParam )
tblQuery = tblQuery % unsafeSQLIdentificatorNaming ( tbl )
tblQuery = tblQuery % unsafeSQLIdentificatorNaming ( tbl )
# 遍历数据库列表
for db in foundTbls . keys ( ) :
for db in foundTbls . keys ( ) :
db = safeSQLIdentificatorNaming ( db )
db = safeSQLIdentificatorNaming ( db ) # 安全命名数据库名
# 如果配置中排除了系统数据库,则跳过
if conf . excludeSysDbs and db in self . excludeDbsList :
if conf . excludeSysDbs and db in self . excludeDbsList :
infoMsg = " skipping system database ' %s ' " % db
infoMsg = " skipping system database ' %s ' " % db
singleTimeLogMessage ( infoMsg )
singleTimeLogMessage ( infoMsg )
continue
continue
# 如果配置中指定了排除的数据库,则跳过
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
infoMsg = " skipping database ' %s ' " % db
infoMsg = " skipping database ' %s ' " % db
singleTimeLogMessage ( infoMsg )
singleTimeLogMessage ( infoMsg )
continue
continue
# 检查是否可以使用 UNION、ERROR、QUERY 注入技术或直接连接
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
query = rootQuery . inband . query . replace ( " %s " , db )
query = rootQuery . inband . query . replace ( " %s " , db )
query + = tblQuery
query + = tblQuery
values = inject . getValue ( query , blind = False , time = False )
values = inject . getValue ( query , blind = False , time = False ) # 执行注入并获取结果
# 如果获取到了表信息,则进行处理
if not isNoneValue ( values ) :
if not isNoneValue ( values ) :
if isinstance ( values , six . string_types ) :
if isinstance ( values , six . string_types ) :
values = [ values ]
values = [ values ]
@ -230,7 +273,9 @@ class Enumeration(GenericEnumeration):
continue
continue
foundTbls [ db ] . append ( foundTbl )
foundTbls [ db ] . append ( foundTbl )
# 如果无法使用上述注入,则使用推断注入搜索表信息
else :
else :
# 输出获取表数量的提示信息
infoMsg = " fetching number of table "
infoMsg = " fetching number of table "
if tblConsider == " 1 " :
if tblConsider == " 1 " :
infoMsg + = " s LIKE "
infoMsg + = " s LIKE "
@ -240,8 +285,8 @@ class Enumeration(GenericEnumeration):
query = rootQuery . blind . count
query = rootQuery . blind . count
query = query . replace ( " %s " , db )
query = query . replace ( " %s " , db )
query + = " AND %s " % tblQuery
query + = " AND %s " % tblQuery
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 isNumPosStrValue ( count ) :
warnMsg = " no table "
warnMsg = " no table "
if tblConsider == " 1 " :
if tblConsider == " 1 " :
@ -252,50 +297,57 @@ class Enumeration(GenericEnumeration):
continue
continue
indexRange = getLimitRange ( count )
indexRange = getLimitRange ( count ) # 生成索引范围
# 遍历表索引,获取每个表名
for index in indexRange :
for index in indexRange :
query = rootQuery . blind . query
query = rootQuery . blind . query
query = query . replace ( " %s " , db )
query = query . replace ( " %s " , db )
query + = " AND %s " % tblQuery
query + = " AND %s " % tblQuery
query = agent . limitQuery ( index , query , tblCond )
query = agent . limitQuery ( index , query , tblCond )
tbl = inject . getValue ( query , union = False , error = False )
tbl = inject . getValue ( query , union = False , error = False ) # 执行推断注入并获取结果
kb . hintValue = tbl
kb . hintValue = tbl
foundTbls [ db ] . append ( tbl )
foundTbls [ db ] . append ( tbl )
# 清理空的数据库表列表
for db , tbls in list ( foundTbls . items ( ) ) :
for db , tbls in list ( foundTbls . items ( ) ) :
if len ( tbls ) == 0 :
if len ( tbls ) == 0 :
foundTbls . pop ( db )
foundTbls . pop ( db )
# 如果没有找到任何表,则输出警告信息
if not foundTbls :
if not foundTbls :
warnMsg = " no databases contain any of the provided tables "
warnMsg = " no databases contain any of the provided tables "
logger . warning ( warnMsg )
logger . warning ( warnMsg )
return
return
conf . dumper . dbTables ( foundTbls )
conf . dumper . dbTables ( foundTbls ) # 将找到的表信息输出到文件
self . dumpFoundTables ( foundTbls )
self . dumpFoundTables ( foundTbls ) # 输出找到的表信息
# 定义 searchColumn 方法,用于搜索指定的列
def searchColumn ( self ) :
def searchColumn ( self ) :
rootQuery = queries [ DBMS . MSSQL ] . search_column
rootQuery = queries [ DBMS . MSSQL ] . search_column # 获取 SQL Server 的列搜索查询语句
foundCols = { }
foundCols = { } # 初始化找到的列字典
dbs = { }
dbs = { } # 初始化数据库字典
whereTblsQuery = " "
whereTblsQuery = " " # 初始化表 WHERE 条件
infoMsgTbl = " "
infoMsgTbl = " " # 初始化表信息
infoMsgDb = " "
infoMsgDb = " " # 初始化数据库信息
colList = conf . col . split ( ' , ' )
colList = conf . col . split ( ' , ' ) # 获取要搜索的列列表
# 如果配置中指定了排除的列,则跳过
if conf . exclude :
if conf . exclude :
colList = [ _ for _ in colList if re . search ( conf . exclude , _ , re . I ) is None ]
colList = [ _ for _ in colList if re . search ( conf . exclude , _ , re . I ) is None ]
origTbl = conf . tbl
origTbl = conf . tbl # 保存原始的表配置
origDb = conf . db
origDb = conf . db # 保存原始的数据库配置
colCond = rootQuery . inband . condition
colCond = rootQuery . inband . condition # 获取列搜索条件
tblCond = rootQuery . inband . condition2
tblCond = rootQuery . inband . condition2 # 获取表搜索条件
colConsider , colCondParam = self . likeOrExact ( " column " )
colConsider , colCondParam = self . likeOrExact ( " column " ) # 获取列搜索的方式 (LIKE 或 EXACT)
# 如果配置中指定了当前数据库,则获取当前数据库
if conf . db == CURRENT_DB :
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
conf . db = self . getCurrentDb ( )
# 如果配置中指定了数据库,则分割数据库字符串,否则获取所有数据库
if conf . db :
if conf . db :
enumDbs = conf . db . split ( ' , ' )
enumDbs = conf . db . split ( ' , ' )
elif not len ( kb . data . cachedDbs ) :
elif not len ( kb . data . cachedDbs ) :
@ -303,30 +355,36 @@ class Enumeration(GenericEnumeration):
else :
else :
enumDbs = kb . data . cachedDbs
enumDbs = kb . data . cachedDbs
# 初始化每个数据库的列搜索结果
for db in enumDbs :
for db in enumDbs :
db = safeSQLIdentificatorNaming ( db )
db = safeSQLIdentificatorNaming ( db )
dbs [ db ] = { }
dbs [ db ] = { }
# 遍历要搜索的列列表
for column in colList :
for column in colList :
column = safeSQLIdentificatorNaming ( column )
column = safeSQLIdentificatorNaming ( column ) # 安全命名列名
conf . db = origDb
conf . db = origDb # 恢复原始的数据库配置
conf . tbl = origTbl
conf . tbl = origTbl # 恢复原始的表配置
# 输出搜索列信息的提示信息
infoMsg = " searching column "
infoMsg = " searching column "
if colConsider == " 1 " :
if colConsider == " 1 " :
infoMsg + = " s LIKE "
infoMsg + = " s LIKE "
infoMsg + = " ' %s ' " % unsafeSQLIdentificatorNaming ( column )
infoMsg + = " ' %s ' " % unsafeSQLIdentificatorNaming ( column )
foundCols [ column ] = { }
foundCols [ column ] = { } # 初始化每个列的搜索结果
# 如果配置中指定了表,则构建表的 WHERE 条件
if conf . tbl :
if conf . tbl :
_ = conf . tbl . split ( ' , ' )
_ = conf . tbl . split ( ' , ' )
whereTblsQuery = " AND ( " + " OR " . join ( " %s = ' %s ' " % ( tblCond , unsafeSQLIdentificatorNaming ( tbl ) ) for tbl in _ ) + " ) "
whereTblsQuery = " AND ( " + " OR " . join ( " %s = ' %s ' " % ( tblCond , unsafeSQLIdentificatorNaming ( tbl ) ) for tbl in _ ) + " ) "
infoMsgTbl = " for table %s ' %s ' " % ( " s " if len ( _ ) > 1 else " " , " , " . join ( tbl for tbl in _ ) )
infoMsgTbl = " for table %s ' %s ' " % ( " s " if len ( _ ) > 1 else " " , " , " . join ( tbl for tbl in _ ) )
# 如果配置中指定了当前数据库,则获取当前数据库
if conf . db == CURRENT_DB :
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
conf . db = self . getCurrentDb ( )
# 如果配置中指定了数据库,则构建数据库信息,否则获取所有数据库
if conf . db :
if conf . db :
_ = conf . db . split ( ' , ' )
_ = conf . db . split ( ' , ' )
infoMsgDb = " in database %s ' %s ' " % ( " s " if len ( _ ) > 1 else " " , " , " . join ( db for db in _ ) )
infoMsgDb = " in database %s ' %s ' " % ( " s " if len ( _ ) > 1 else " " , " , " . join ( db for db in _ ) )
@ -337,30 +395,35 @@ class Enumeration(GenericEnumeration):
logger . info ( " %s %s %s " % ( infoMsg , infoMsgTbl , infoMsgDb ) )
logger . info ( " %s %s %s " % ( infoMsg , infoMsgTbl , infoMsgDb ) )
# 构建列搜索查询条件
colQuery = " %s %s " % ( colCond , colCondParam )
colQuery = " %s %s " % ( colCond , colCondParam )
colQuery = colQuery % unsafeSQLIdentificatorNaming ( column )
colQuery = colQuery % unsafeSQLIdentificatorNaming ( column )
# 遍历数据库列表
for db in ( _ for _ in dbs if _ ) :
for db in ( _ for _ in dbs if _ ) :
db = safeSQLIdentificatorNaming ( db )
db = safeSQLIdentificatorNaming ( db ) # 安全命名数据库名
# 如果配置中排除了系统数据库,则跳过
if conf . excludeSysDbs and db in self . excludeDbsList :
if conf . excludeSysDbs and db in self . excludeDbsList :
continue
continue
# 如果配置中指定了排除的数据库,则跳过
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
continue
continue
# 检查是否可以使用 UNION、ERROR、QUERY 注入技术或直接连接
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
query = rootQuery . inband . query % ( db , db , db , db , db , db )
query = rootQuery . inband . query % ( db , db , db , db , db , db )
query + = " AND %s " % colQuery . replace ( " [DB] " , db )
query + = " AND %s " % colQuery . replace ( " [DB] " , db )
query + = whereTblsQuery . replace ( " [DB] " , db )
query + = whereTblsQuery . replace ( " [DB] " , db )
values = inject . getValue ( query , blind = False , time = False )
values = inject . getValue ( query , blind = False , time = False ) # 执行注入并获取结果
# 如果获取到了列信息,则进行处理
if not isNoneValue ( values ) :
if not isNoneValue ( values ) :
if isinstance ( values , six . string_types ) :
if isinstance ( values , six . string_types ) :
values = [ values ]
values = [ values ]
for foundTbl in values :
for foundTbl in values :
foundTbl = safeSQLIdentificatorNaming ( unArrayizeValue ( foundTbl ) , True )
foundTbl = safeSQLIdentificatorNaming ( unArrayizeValue ( foundTbl ) , True ) # 安全命名表名
if foundTbl is None :
if foundTbl is None :
continue
continue
@ -373,7 +436,7 @@ class Enumeration(GenericEnumeration):
conf . tbl = foundTbl
conf . tbl = foundTbl
conf . col = column
conf . col = column
self . getColumns ( onlyColNames = True , colTuple = ( colConsider , colCondParam ) , bruteForce = False )
self . getColumns ( onlyColNames = True , colTuple = ( colConsider , colCondParam ) , bruteForce = False ) # 获取列信息
if db in kb . data . cachedColumns and foundTbl in kb . data . cachedColumns [ db ] and not isNoneValue ( kb . data . cachedColumns [ db ] [ foundTbl ] ) :
if db in kb . data . cachedColumns and foundTbl in kb . data . cachedColumns [ db ] and not isNoneValue ( kb . data . cachedColumns [ db ] [ foundTbl ] ) :
dbs [ db ] [ foundTbl ] . update ( kb . data . cachedColumns [ db ] [ foundTbl ] )
dbs [ db ] [ foundTbl ] . update ( kb . data . cachedColumns [ db ] [ foundTbl ] )
@ -386,9 +449,11 @@ class Enumeration(GenericEnumeration):
foundCols [ column ] [ db ] . append ( foundTbl )
foundCols [ column ] [ db ] . append ( foundTbl )
else :
else :
foundCols [ column ] [ db ] = [ foundTbl ]
foundCols [ column ] [ db ] = [ foundTbl ]
# 如果无法使用上述注入,则使用推断注入搜索列信息
else :
else :
foundCols [ column ] [ db ] = [ ]
foundCols [ column ] [ db ] = [ ]
# 输出获取包含该列的表数量的提示信息
infoMsg = " fetching number of tables containing column "
infoMsg = " fetching number of tables containing column "
if colConsider == " 1 " :
if colConsider == " 1 " :
infoMsg + = " s LIKE "
infoMsg + = " s LIKE "
@ -399,8 +464,9 @@ class Enumeration(GenericEnumeration):
query = query % ( db , db , db , db , db , db )
query = query % ( db , db , db , db , db , db )
query + = " AND %s " % colQuery . replace ( " [DB] " , db )
query + = " AND %s " % colQuery . replace ( " [DB] " , db )
query + = whereTblsQuery . replace ( " [DB] " , db )
query + = whereTblsQuery . replace ( " [DB] " , db )
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 isNumPosStrValue ( count ) :
warnMsg = " no tables contain column "
warnMsg = " no tables contain column "
if colConsider == " 1 " :
if colConsider == " 1 " :
@ -411,18 +477,19 @@ class Enumeration(GenericEnumeration):
continue
continue
indexRange = getLimitRange ( count )
indexRange = getLimitRange ( count ) # 生成索引范围
# 遍历表索引,获取每个表名
for index in indexRange :
for index in indexRange :
query = rootQuery . blind . query
query = rootQuery . blind . query
query = query % ( db , db , db , db , db , db )
query = query % ( db , db , db , db , db , db )
query + = " AND %s " % colQuery . replace ( " [DB] " , db )
query + = " AND %s " % colQuery . replace ( " [DB] " , db )
query + = whereTblsQuery . replace ( " [DB] " , db )
query + = whereTblsQuery . replace ( " [DB] " , db )
query = agent . limitQuery ( index , query , colCond . replace ( " [DB] " , db ) )
query = agent . limitQuery ( index , query , colCond . replace ( " [DB] " , db ) )
tbl = inject . getValue ( query , union = False , error = False )
tbl = inject . getValue ( query , union = False , error = False ) # 执行推断注入并获取结果
kb . hintValue = tbl
kb . hintValue = tbl
tbl = safeSQLIdentificatorNaming ( tbl , True )
tbl = safeSQLIdentificatorNaming ( tbl , True ) # 安全命名表名
if tbl not in dbs [ db ] :
if tbl not in dbs [ db ] :
dbs [ db ] [ tbl ] = { }
dbs [ db ] [ tbl ] = { }
@ -432,7 +499,7 @@ class Enumeration(GenericEnumeration):
conf . tbl = tbl
conf . tbl = tbl
conf . col = column
conf . col = column
self . getColumns ( onlyColNames = True , colTuple = ( colConsider , colCondParam ) , bruteForce = False )
self . getColumns ( onlyColNames = True , colTuple = ( colConsider , colCondParam ) , bruteForce = False ) # 获取列信息
if db in kb . data . cachedColumns and tbl in kb . data . cachedColumns [ db ] :
if db in kb . data . cachedColumns and tbl in kb . data . cachedColumns [ db ] :
dbs [ db ] [ tbl ] . update ( kb . data . cachedColumns [ db ] [ tbl ] )
dbs [ db ] [ tbl ] . update ( kb . data . cachedColumns [ db ] [ tbl ] )
@ -440,7 +507,7 @@ class Enumeration(GenericEnumeration):
else :
else :
dbs [ db ] [ tbl ] [ column ] = None
dbs [ db ] [ tbl ] [ column ] = None
foundCols [ column ] [ db ] . append ( tbl )
foundCols [ column ] [ db ] . append ( tbl ) # 将找到的表添加到结果中
conf . dumper . dbColumns ( foundCols , colConsider , dbs )
conf . dumper . dbColumns ( foundCols , colConsider , dbs ) # 将找到的列信息输出到文件
self . dumpFoundColumn ( dbs , foundCols , colConsider )
self . dumpFoundColumn ( dbs , foundCols , colConsider ) # 输出找到的列信息