diff --git a/data/txt/sha256sums.txt b/data/txt/sha256sums.txt index 1059767f5..598648de0 100644 --- a/data/txt/sha256sums.txt +++ b/data/txt/sha256sums.txt @@ -189,7 +189,7 @@ ccc4a717e887652b1fcce073d9409d9c59a3b28548c703a9e453d15845f90cd7 lib/core/patch 48797d6c34dd9bb8a53f7f3794c85f4288d82a9a1d6be7fcf317d388cb20d4b3 lib/core/replication.py 0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py 888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py -f47aed1aa1a986dc2d3789358a34f79aa1111e7ab8747c4fba4dfe3443f778a0 lib/core/settings.py +65603f9bbf42cd67a1cf9b3f6277b3af3fdf6b3678fcaa2fe21fe09961f9316c lib/core/settings.py cd5a66deee8963ba8e7e9af3dd36eb5e8127d4d68698811c29e789655f507f82 lib/core/shell.py bcb5d8090d5e3e0ef2a586ba09ba80eef0c6d51feb0f611ed25299fbb254f725 lib/core/subprocessng.py 70ea3768f1b3062b22d20644df41c86238157ec80dd43da40545c620714273c6 lib/core/target.py @@ -214,7 +214,7 @@ bc61bc944b81a7670884f82231033a6ac703324b34b071c9834886a92e249d0e lib/request/ch 390cc4882ba9c76e16a5376ba6d856079e7cb47a3e4ee11925139e637ce05050 lib/request/comparison.py b9e2db44d265909792f6cc821ff910727b14aa2d5063c74b0f2ea6d40c4f3d9d lib/request/connect.py 8e06682280fce062eef6174351bfebcb6040e19976acff9dc7b3699779783498 lib/request/direct.py -cf019248253a5d7edb7bc474aa020b9e8625d73008a463c56ba2b539d7f2d8ec lib/request/dns.py +05198477dbdeb6c405059eb21cbbcf9cb6804cc54a0f2a1d11741bfc6cbb7ca2 lib/request/dns.py 92c81cc31ff4a396723242058fb2152c9e9745f8412d01ea74480b048a53af6c lib/request/httpshandler.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/request/__init__.py 7a0ac2522213e756348fd871a7af74cc963bdc82f9d7ade57be5de42b5bf7cab lib/request/inject.py @@ -236,7 +236,7 @@ f522436fbd14bdab090a1d305fcac0361800cb8e36c8cbcb47933298376a71e0 lib/takeover/r 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/blind/__init__.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/dns/__init__.py 3df9839fb92a81d46b6194d7adacb43f391efb78b071783c132e8d596ecbfaf1 lib/techniques/dns/test.py -2934514a60cbcd48675053a73f785b4c7bfe606b51c34ae81a86818362ec4672 lib/techniques/dns/use.py +74ca78082dcd20b3faf07cc944cd65ea552996df40e6fb58d0a011b262528456 lib/techniques/dns/use.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/error/__init__.py 5bbef46c16e34fd80e3f9f0e9aa255ce2e39be0d0e57479e25890b041c7efc7d lib/techniques/error/use.py 1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/__init__.py diff --git a/lib/core/settings.py b/lib/core/settings.py index 604303249..e48738fb1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from lib.core.enums import OS from thirdparty import six # sqlmap version (...) -VERSION = "1.10.6.134" +VERSION = "1.10.6.135" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) @@ -809,6 +809,11 @@ MAX_STABILITY_DELAY = 0.5 # Reference: http://www.tcpipguide.com/free/t_DNSLabelsNamesandSyntaxRules.htm MAX_DNS_LABEL = 63 +# Maximum number of (most recent) DNS resolution requests retained by the DNS server (bounded so +# that unrelated/stray traffic to the listening :53 socket cannot grow memory without limit; the +# value is popped right after it is triggered, so only recent entries ever matter) +MAX_DNS_REQUESTS = 1000 + # Alphabet used for prefix and suffix strings of name resolution requests in DNS technique (excluding hexadecimal chars for not mixing with inner content) DNS_BOUNDARIES_ALPHABET = re.sub(r"[a-fA-F]", "", string.ascii_letters) diff --git a/lib/request/dns.py b/lib/request/dns.py index 1be548882..ffd389a4d 100644 --- a/lib/request/dns.py +++ b/lib/request/dns.py @@ -8,6 +8,7 @@ See the file 'LICENSE' for copying permission from __future__ import print_function import binascii +import collections import os import re import socket @@ -15,6 +16,11 @@ import struct import threading import time +try: + from lib.core.settings import MAX_DNS_REQUESTS +except ImportError: + MAX_DNS_REQUESTS = 1000 # fallback so this module stays runnable standalone + class DNSQuery(object): """ >>> DNSQuery(b'|K\\x01 \\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x01\\x03www\\x06google\\x03com\\x00\\x00\\x01\\x00\\x01\\x00\\x00)\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\n\\x00\\x08O4|Np!\\x1d\\xb3')._query == b"www.google.com." @@ -74,7 +80,7 @@ class DNSServer(object): def __init__(self): self._check_localhost() - self._requests = [] + self._requests = collections.deque(maxlen=MAX_DNS_REQUESTS) self._lock = threading.Lock() try: @@ -140,12 +146,28 @@ class DNSServer(object): self._initialized = True while True: - data, addr = self._socket.recvfrom(1024) - _ = DNSQuery(data) - self._socket.sendto(_.response("127.0.0.1"), addr) + try: + data, addr = self._socket.recvfrom(1024) + except KeyboardInterrupt: + raise + except Exception: + break # socket closed/broken - stop serving (e.g. program exit) - with self._lock: - self._requests.append(_._query) + # Note: a single malformed packet or a transient send error must NOT kill the + # server thread (otherwise all subsequent DNS exfiltration is silently lost). + # The query is recorded BEFORE responding, so the exfiltrated data is captured + # even if crafting/sending the (fake) resolution response fails. + try: + _ = DNSQuery(data) + + with self._lock: + self._requests.append(_._query) + + self._socket.sendto(_.response("127.0.0.1"), addr) + except KeyboardInterrupt: + raise + except Exception: + pass except KeyboardInterrupt: raise diff --git a/lib/techniques/dns/use.py b/lib/techniques/dns/use.py index 78854c012..1f0d21f31 100644 --- a/lib/techniques/dns/use.py +++ b/lib/techniques/dns/use.py @@ -84,7 +84,10 @@ def dnsUse(payload, expression): _ = conf.dnsServer.pop(prefix, suffix) if _: - _ = extractRegexResult(r"%s\.(?P.+)\.%s" % (prefix, suffix), _, re.I) + # Note: non-greedy so a '--dns-domain' label that happens to match the random + # suffix can't make the match run past the real boundary (the boundary alphabet + # excludes hex characters, so it can never under-match into the hex payload) + _ = extractRegexResult(r"%s\.(?P.+?)\.%s" % (prefix, suffix), _, re.I) _ = decodeDbmsHexValue(_) output = (output or "") + _ offset += len(_)