From 3f6b53f5f341890f09c2ea7d63cefc6f3ba73e6f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 5 Mar 2019 12:24:41 +0100 Subject: [PATCH] Fixes #3515 (and reimplements #1062) --- lib/core/common.py | 20 ++++++++++++++------ lib/core/settings.py | 6 +++--- lib/request/connect.py | 23 ++++++----------------- txt/checksum.md5 | 6 +++--- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 22fe12f0c..8bc0fc5f9 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -16,6 +16,7 @@ import hashlib import httplib import inspect import json +import keyword import locale import logging import ntpath @@ -115,6 +116,7 @@ from lib.core.settings import DEV_EMAIL_ADDRESS from lib.core.settings import DUMMY_USER_INJECTION from lib.core.settings import DYNAMICITY_BOUNDARY_LENGTH from lib.core.settings import ERROR_PARSING_REGEXES +from lib.core.settings import EVALCODE_ENCODED_PREFIX from lib.core.settings import FILE_PATH_REGEXES from lib.core.settings import FORCE_COOKIE_EXPIRATION_TIME from lib.core.settings import FORM_SEARCH_REGEX @@ -4816,21 +4818,27 @@ def safeVariableNaming(value): """ Returns escaped safe-representation of a given variable name that can be used in Python evaluated code - >>> safeVariableNaming("foo bar") - 'foo__SAFE__20bar' + >>> safeVariableNaming("class.id") + 'EVAL_636c6173732e6964' """ - return re.sub(r"[^\w]", lambda match: "%s%02x" % (SAFE_VARIABLE_MARKER, ord(match.group(0))), value) + if value in keyword.kwlist or re.search(r"\A[^a-zA-Z]|[^\w]", value): + value = "%s%s" % (EVALCODE_ENCODED_PREFIX, value.encode(UNICODE_ENCODING).encode("hex")) + + return value def unsafeVariableNaming(value): """ Returns unescaped safe-representation of a given variable name - >>> unsafeVariableNaming("foo__SAFE__20bar") - 'foo bar' + >>> unsafeVariableNaming("EVAL_636c6173732e6964") + u'class.id' """ - return re.sub(r"%s([0-9a-f]{2})" % SAFE_VARIABLE_MARKER, lambda match: match.group(1).decode("hex"), value) + if value.startswith(EVALCODE_ENCODED_PREFIX): + value = value[len(EVALCODE_ENCODED_PREFIX):].decode("hex").decode(UNICODE_ENCODING) + + return value def firstNotNone(*args): """ diff --git a/lib/core/settings.py b/lib/core/settings.py index c9304ca75..f56eccfd0 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME from lib.core.enums import OS # sqlmap version (...) -VERSION = "1.3.3.4" +VERSION = "1.3.3.5" 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) @@ -761,8 +761,8 @@ METASPLOIT_SESSION_TIMEOUT = 120 # Reference: http://www.postgresql.org/docs/9.0/static/catalog-pg-largeobject.html LOBLKSIZE = 2048 -# Suffix used to mark variables having keyword names -EVALCODE_KEYWORD_SUFFIX = "_KEYWORD" +# Prefix used to mark special variables (e.g. keywords, having special chars, etc.) +EVALCODE_ENCODED_PREFIX = "EVAL_" # Reference: http://www.cookiecentral.com/faq/#3.5 NETSCAPE_FORMAT_HEADER_COOKIES = "# Netscape HTTP Cookie File." diff --git a/lib/request/connect.py b/lib/request/connect.py index f147fe8c2..2d6bc8338 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -8,7 +8,6 @@ See the file 'LICENSE' for copying permission import binascii import compiler import httplib -import keyword import logging import re import socket @@ -92,7 +91,7 @@ from lib.core.settings import DEFAULT_CONTENT_TYPE from lib.core.settings import DEFAULT_COOKIE_DELIMITER from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import DEFAULT_USER_AGENT -from lib.core.settings import EVALCODE_KEYWORD_SUFFIX +from lib.core.settings import EVALCODE_ENCODED_PREFIX from lib.core.settings import HTTP_ACCEPT_HEADER_VALUE from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE from lib.core.settings import MAX_CONNECTION_CHUNK_SIZE @@ -1070,7 +1069,6 @@ class Connect(object): delimiter = conf.paramDel or DEFAULT_GET_POST_DELIMITER variables = {"uri": uri, "lastPage": threadData.lastPage, "_locals": locals()} originals = {} - keywords = keyword.kwlist if not get and PLACE.URI in conf.parameters: query = urlparse.urlsplit(uri).query or "" @@ -1085,8 +1083,6 @@ class Connect(object): if safeVariableNaming(name) != name: conf.evalCode = re.sub(r"\b%s\b" % re.escape(name), safeVariableNaming(name), conf.evalCode) name = safeVariableNaming(name) - elif name in keywords: - name = "%s%s" % (name, EVALCODE_KEYWORD_SUFFIX) value = urldecode(value, convall=True, spaceplus=(item == post and kb.postSpaceToPlus)) variables[name] = value @@ -1098,8 +1094,6 @@ class Connect(object): if safeVariableNaming(name) != name: conf.evalCode = re.sub(r"\b%s\b" % re.escape(name), safeVariableNaming(name), conf.evalCode) name = safeVariableNaming(name) - elif name in keywords: - name = "%s%s" % (name, EVALCODE_KEYWORD_SUFFIX) value = urldecode(value, convall=True) variables[name] = value @@ -1109,20 +1103,20 @@ class Connect(object): except SyntaxError as ex: if ex.text: original = replacement = ex.text.strip() + if '=' in original: name, value = original.split('=', 1) name = name.strip() if safeVariableNaming(name) != name: replacement = re.sub(r"\b%s\b" % re.escape(name), safeVariableNaming(name), replacement) - elif name in keywords: - replacement = re.sub(r"\b%s\b" % re.escape(name), "%s%s" % (name, EVALCODE_KEYWORD_SUFFIX), replacement) else: for _ in re.findall(r"[A-Za-z_]+", original)[::-1]: - if _ in keywords: - replacement = replacement.replace(_, "%s%s" % (_, EVALCODE_KEYWORD_SUFFIX)) + if safeVariableNaming(_) != _: + replacement = replacement.replace(_, safeVariableNaming(_)) break + if original == replacement: - conf.evalCode = conf.evalCode.replace(EVALCODE_KEYWORD_SUFFIX, "") + conf.evalCode = conf.evalCode.replace(EVALCODE_ENCODED_PREFIX, "") break else: conf.evalCode = conf.evalCode.replace(getUnicode(ex.text.strip(), UNICODE_ENCODING), replacement) @@ -1135,11 +1129,6 @@ class Connect(object): evaluateCode(conf.evalCode, variables) for variable in list(variables.keys()): - if variable.endswith(EVALCODE_KEYWORD_SUFFIX): - value = variables[variable] - del variables[variable] - variables[variable.replace(EVALCODE_KEYWORD_SUFFIX, "")] = value - if unsafeVariableNaming(variable) != variable: value = variables[variable] del variables[variable] diff --git a/txt/checksum.md5 b/txt/checksum.md5 index 9c8803f5d..5520305cf 100644 --- a/txt/checksum.md5 +++ b/txt/checksum.md5 @@ -30,7 +30,7 @@ c1da277517c7ec4c23e953a51b51e203 lib/controller/handler.py fb6be55d21a70765e35549af2484f762 lib/controller/__init__.py ed7874be0d2d3802f3d20184f2b280d5 lib/core/agent.py a932126e7d80e545c5d44af178d0bc0c lib/core/bigarray.py -9deec4762d61e057b6e069b2538bdcf8 lib/core/common.py +8996b4b377b859dc69de323416615f2f lib/core/common.py de8d27ae6241163ff9e97aa9e7c51a18 lib/core/convert.py abcb1121eb56d3401839d14e8ed06b6e lib/core/data.py 00828c4455321b6987e3f882f4ef4f92 lib/core/datatype.py @@ -50,7 +50,7 @@ d5ef43fe3cdd6c2602d7db45651f9ceb lib/core/readlineng.py 7d8a22c582ad201f65b73225e4456170 lib/core/replication.py 3179d34f371e0295dd4604568fb30bcd lib/core/revision.py d6269c55789f78cf707e09a0f5b45443 lib/core/session.py -918a8651a9872a33ddb04f82ac3360c3 lib/core/settings.py +1cd62a025c607338eb55d673375b4444 lib/core/settings.py 4483b4a5b601d8f1c4281071dff21ecc lib/core/shell.py 10fd19b0716ed261e6d04f311f6f527c lib/core/subprocessng.py 43772ea73e9e3d446f782af591cb4eda lib/core/target.py @@ -72,7 +72,7 @@ adcecd2d6a8667b22872a563eb83eac0 lib/parse/payloads.py e4ea70bcd461f5176867dcd89d372386 lib/request/basicauthhandler.py b23163d485e0dbc038cbf1ba80be11da lib/request/basic.py fc25d951217077fe655ed2a3a81552ae lib/request/comparison.py -3925fef5710ac4e96b85c808df1c2f6a lib/request/connect.py +d2e7673ed4838a321b825ea1854ea2c0 lib/request/connect.py 43005bd6a78e9cf0f3ed2283a1cb122e lib/request/direct.py 2b7509ba38a667c61cefff036ec4ca6f lib/request/dns.py ceac6b3bf1f726f8ff43c6814e9d7281 lib/request/httpshandler.py