|
|
|
@ -314,30 +314,42 @@ def _goBooleanProxy(expression):
|
|
|
|
|
Retrieve the output of a boolean based SQL query
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# 初始化技术
|
|
|
|
|
initTechnique(getTechnique())
|
|
|
|
|
|
|
|
|
|
# 如果配置了dns域名
|
|
|
|
|
if conf.dnsDomain:
|
|
|
|
|
# 获取查询语句
|
|
|
|
|
query = agent.prefixQuery(getTechniqueData().vector)
|
|
|
|
|
query = agent.suffixQuery(query)
|
|
|
|
|
# 获取payload
|
|
|
|
|
payload = agent.payload(newValue=query)
|
|
|
|
|
# 执行dns查询
|
|
|
|
|
output = _goDns(payload, expression)
|
|
|
|
|
|
|
|
|
|
# 如果查询结果不为空,则返回
|
|
|
|
|
if output is not None:
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
# 获取查询语句
|
|
|
|
|
vector = getTechniqueData().vector
|
|
|
|
|
vector = vector.replace(INFERENCE_MARKER, expression)
|
|
|
|
|
query = agent.prefixQuery(vector)
|
|
|
|
|
query = agent.suffixQuery(query)
|
|
|
|
|
# 获取payload
|
|
|
|
|
payload = agent.payload(newValue=query)
|
|
|
|
|
|
|
|
|
|
# 判断是否是时间相关的技术
|
|
|
|
|
timeBasedCompare = getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)
|
|
|
|
|
|
|
|
|
|
# 从hash数据库中获取查询结果
|
|
|
|
|
output = hashDBRetrieve(expression, checkConf=True)
|
|
|
|
|
|
|
|
|
|
# 如果查询结果为空,则执行查询
|
|
|
|
|
if output is None:
|
|
|
|
|
output = Request.queryPage(payload, timeBasedCompare=timeBasedCompare, raise404=False)
|
|
|
|
|
|
|
|
|
|
# 如果查询结果不为空,则将结果写入hash数据库
|
|
|
|
|
if output is not None:
|
|
|
|
|
hashDBWrite(expression, output)
|
|
|
|
|
|
|
|
|
@ -349,8 +361,10 @@ def _goUnion(expression, unpack=True, dump=False):
|
|
|
|
|
injection vulnerability on the affected parameter.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# 执行联合查询
|
|
|
|
|
output = unionUse(expression, unpack=unpack, dump=dump)
|
|
|
|
|
|
|
|
|
|
# 如果输出是字符串类型,则解析输出
|
|
|
|
|
if isinstance(output, six.string_types):
|
|
|
|
|
output = parseUnionPage(output)
|
|
|
|
|
|
|
|
|
@ -364,6 +378,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
|
|
|
|
affected parameter.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# 如果配置了hex转换,并且数据库类型已知,则设置字符集类型为十六进制
|
|
|
|
|
if conf.hexConvert and expected != EXPECTED.BOOL and Backend.getIdentifiedDbms():
|
|
|
|
|
if not hasattr(queries[Backend.getIdentifiedDbms()], "hex"):
|
|
|
|
|
warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms()
|
|
|
|
@ -372,31 +387,39 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
|
|
|
|
else:
|
|
|
|
|
charsetType = CHARSET_TYPE.HEXADECIMAL
|
|
|
|
|
|
|
|
|
|
# 设置安全字符编码和恢复值
|
|
|
|
|
kb.safeCharEncode = safeCharEncode
|
|
|
|
|
kb.resumeValues = resumeValue
|
|
|
|
|
|
|
|
|
|
# 将表达式中的关键字转换为大写
|
|
|
|
|
for keyword in GET_VALUE_UPPERCASE_KEYWORDS:
|
|
|
|
|
expression = re.sub(r"(?i)(\A|\(|\)|\s)%s(\Z|\(|\)|\s)" % keyword, r"\g<1>%s\g<2>" % keyword, expression)
|
|
|
|
|
|
|
|
|
|
# 如果抑制输出不为空,则设置当前线程的抑制输出
|
|
|
|
|
if suppressOutput is not None:
|
|
|
|
|
pushValue(getCurrentThreadData().disableStdOut)
|
|
|
|
|
getCurrentThreadData().disableStdOut = suppressOutput
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# 保存当前数据库和表
|
|
|
|
|
pushValue(conf.db)
|
|
|
|
|
pushValue(conf.tbl)
|
|
|
|
|
|
|
|
|
|
# 如果期望的输出是布尔类型
|
|
|
|
|
if expected == EXPECTED.BOOL:
|
|
|
|
|
forgeCaseExpression = booleanExpression = expression
|
|
|
|
|
|
|
|
|
|
# 如果表达式以SELECT开头,则将表达式转换为布尔表达式
|
|
|
|
|
if expression.startswith("SELECT "):
|
|
|
|
|
booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1")
|
|
|
|
|
else:
|
|
|
|
|
forgeCaseExpression = agent.forgeCaseStatement(expression)
|
|
|
|
|
|
|
|
|
|
# 如果直接执行
|
|
|
|
|
if conf.direct:
|
|
|
|
|
value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression)
|
|
|
|
|
|
|
|
|
|
# 如果使用了任何公开的技术
|
|
|
|
|
elif any(isTechniqueAvailable(_) for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True)):
|
|
|
|
|
query = cleanQuery(expression)
|
|
|
|
|
query = expandAsteriskForColumns(query)
|
|
|
|
@ -459,52 +482,72 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
|
|
|
|
warnMsg += "(%s) " % _
|
|
|
|
|
singleTimeWarnMessage(warnMsg)
|
|
|
|
|
|
|
|
|
|
# 如果启用了盲注,并且布尔技术可用,且未找到结果,则设置布尔技术
|
|
|
|
|
if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
|
|
|
|
|
setTechnique(PAYLOAD.TECHNIQUE.BOOLEAN)
|
|
|
|
|
|
|
|
|
|
# 如果期望的结果是布尔值,则使用_goBooleanProxy函数获取结果
|
|
|
|
|
if expected == EXPECTED.BOOL:
|
|
|
|
|
value = _goBooleanProxy(booleanExpression)
|
|
|
|
|
# 否则,使用_goInferenceProxy函数获取结果
|
|
|
|
|
else:
|
|
|
|
|
value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump)
|
|
|
|
|
|
|
|
|
|
# 计数加一
|
|
|
|
|
count += 1
|
|
|
|
|
# 如果结果不为空,或者结果为空且期望结果为空,或者计数大于等于最大技术数,则设置found为True
|
|
|
|
|
found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE
|
|
|
|
|
|
|
|
|
|
# 如果启用了时间注入,并且时间或堆栈技术可用,且未找到结果,则设置时间或堆栈技术
|
|
|
|
|
if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found:
|
|
|
|
|
# 使用正则表达式匹配表达式中的FROM和ORDER BY
|
|
|
|
|
match = re.search(r"\bFROM\b ([^ ]+).+ORDER BY ([^ ]+)", expression)
|
|
|
|
|
# 将匹配结果设置为kb.responseTimeMode
|
|
|
|
|
kb.responseTimeMode = "%s|%s" % (match.group(1), match.group(2)) if match else None
|
|
|
|
|
|
|
|
|
|
# 如果时间技术可用,则设置时间技术
|
|
|
|
|
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
|
|
|
|
|
setTechnique(PAYLOAD.TECHNIQUE.TIME)
|
|
|
|
|
# 否则,设置堆栈技术
|
|
|
|
|
else:
|
|
|
|
|
setTechnique(PAYLOAD.TECHNIQUE.STACKED)
|
|
|
|
|
|
|
|
|
|
# 如果期望的结果是布尔值,则使用_goBooleanProxy函数获取结果
|
|
|
|
|
if expected == EXPECTED.BOOL:
|
|
|
|
|
value = _goBooleanProxy(booleanExpression)
|
|
|
|
|
# 否则,使用_goInferenceProxy函数获取结果
|
|
|
|
|
else:
|
|
|
|
|
value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有找到可用的注入类型,则抛出异常
|
|
|
|
|
errMsg = "none of the injection types identified can be "
|
|
|
|
|
errMsg += "leveraged to retrieve queries output"
|
|
|
|
|
raise SqlmapNotVulnerableException(errMsg)
|
|
|
|
|
|
|
|
|
|
# 最后,恢复kb.resumeValues和kb.responseTimeMode的值
|
|
|
|
|
finally:
|
|
|
|
|
kb.resumeValues = True
|
|
|
|
|
kb.responseTimeMode = None
|
|
|
|
|
|
|
|
|
|
# 从kb中弹出tbl和db的值
|
|
|
|
|
conf.tbl = popValue()
|
|
|
|
|
conf.db = popValue()
|
|
|
|
|
|
|
|
|
|
# 如果suppressOutput不为None,则禁用标准输出
|
|
|
|
|
if suppressOutput is not None:
|
|
|
|
|
getCurrentThreadData().disableStdOut = popValue()
|
|
|
|
|
|
|
|
|
|
# 设置kb.safeCharEncode为False
|
|
|
|
|
kb.safeCharEncode = False
|
|
|
|
|
|
|
|
|
|
# 如果没有启用测试模式、dummy、离线、noCast、hexConvert,且结果为空,且数据库已识别,且kb.fingerprinted为True,则抛出异常或警告
|
|
|
|
|
if not any((kb.testMode, conf.dummy, conf.offline, conf.noCast, conf.hexConvert)) and value is None and Backend.getDbms() and conf.dbmsHandler and kb.fingerprinted:
|
|
|
|
|
# 如果启用了abortOnEmpty,则抛出异常
|
|
|
|
|
if conf.abortOnEmpty:
|
|
|
|
|
errMsg = "aborting due to empty data retrieval"
|
|
|
|
|
logger.critical(errMsg)
|
|
|
|
|
raise SystemExit
|
|
|
|
|
# 否则,抛出警告
|
|
|
|
|
else:
|
|
|
|
|
warnMsg = "in case of continuous data retrieval problems you are advised to try "
|
|
|
|
|
warnMsg += "a switch '--no-cast' "
|
|
|
|
@ -543,24 +586,35 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
|
|
|
|
|
return extractExpectedValue(value, expected)
|
|
|
|
|
|
|
|
|
|
def goStacked(expression, silent=False):
|
|
|
|
|
# 检查是否已经设置了堆叠注入技术
|
|
|
|
|
if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data:
|
|
|
|
|
# 如果已经设置了堆叠注入技术,则直接设置
|
|
|
|
|
setTechnique(PAYLOAD.TECHNIQUE.STACKED)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有设置堆叠注入技术,则遍历所有公开的技术
|
|
|
|
|
for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True):
|
|
|
|
|
# 获取技术的数据
|
|
|
|
|
_ = getTechniqueData(technique)
|
|
|
|
|
# 如果数据存在,并且标题中包含"stacked",则设置该技术
|
|
|
|
|
if _ and "stacked" in _["title"].lower():
|
|
|
|
|
setTechnique(technique)
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
# 清理查询语句
|
|
|
|
|
expression = cleanQuery(expression)
|
|
|
|
|
|
|
|
|
|
# 如果配置了直接执行,则直接执行查询语句
|
|
|
|
|
if conf.direct:
|
|
|
|
|
return direct(expression)
|
|
|
|
|
|
|
|
|
|
# 构造查询语句
|
|
|
|
|
query = agent.prefixQuery(";%s" % expression)
|
|
|
|
|
query = agent.suffixQuery(query)
|
|
|
|
|
# 构造payload
|
|
|
|
|
payload = agent.payload(newValue=query)
|
|
|
|
|
# 执行查询语句
|
|
|
|
|
Request.queryPage(payload, content=False, silent=silent, noteResponseTime=False, timeBasedCompare="SELECT" in (payload or "").upper())
|
|
|
|
|
|
|
|
|
|
def checkBooleanExpression(expression, expectingNone=True):
|
|
|
|
|
# 检查布尔表达式
|
|
|
|
|
return getValue(expression, expected=EXPECTED.BOOL, charsetType=CHARSET_TYPE.BINARY, suppressOutput=True, expectingNone=expectingNone)
|
|
|
|
|