From b528fc07f9407d263c5322414a628404ef2cde77 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 10 Feb 2022 22:30:17 +0100 Subject: [PATCH] Update for #4928 --- lib/core/option.py | 1 + lib/core/settings.py | 2 +- lib/core/target.py | 11 +++++++++++ lib/core/testing.py | 1 + lib/request/connect.py | 15 +++++++++++++-- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index cd16e5d69..aec32a0c2 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2116,6 +2116,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.pageStable = None kb.partRun = None kb.permissionFlag = False + kb.place = None kb.postHint = None kb.postSpaceToPlus = False kb.postUrlEncode = True diff --git a/lib/core/settings.py b/lib/core/settings.py index 10c1bbff1..90dc3f5d8 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty import six from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.6.1.7" +VERSION = "1.6.2.0" 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) diff --git a/lib/core/target.py b/lib/core/target.py index 0b5ed7cd4..4766775ba 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -26,8 +26,10 @@ from lib.core.common import readInput from lib.core.common import removePostHintPrefix from lib.core.common import resetCookieJar from lib.core.common import safeStringFormat +from lib.core.common import unArrayizeValue from lib.core.common import urldecode from lib.core.compat import xrange +from lib.core.convert import decodeBase64 from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb @@ -741,6 +743,15 @@ def initTargetEnv(): setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original) kb.postSpaceToPlus = '+' in original + if conf.data and unArrayizeValue(conf.base64Parameter) == HTTPMETHOD.POST: + if '=' not in conf.data.strip('='): + try: + original = conf.data + conf.data = _(decodeBase64(conf.data, binary=False)) + setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original) + except: + pass + match = re.search(INJECT_HERE_REGEX, "%s %s %s" % (conf.url, conf.data, conf.httpHeaders)) kb.customInjectionMark = match.group(0) if match else CUSTOM_INJECTION_MARK_CHAR diff --git a/lib/core/testing.py b/lib/core/testing.py index d19423d4f..bf3a06732 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -65,6 +65,7 @@ def vulnTest(): ("-u --flush-session --banner --invalid-logical --technique=B --predict-output --test-filter=\"OR boolean\" --tamper=space2dash", ("banner: '3.", " LIKE ")), ("-u --flush-session --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e; id=1*; id2=2\" --tables --union-cols=3", ("might be injectable", "Cookie #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner --count -T users", ("NULL connection is supported with HEAD method", "banner: '3.", "users | 5")), + ("-u --data=\"aWQ9MQ==\" --flush-session --base64=POST -v 6", ("aWQ9MTtXQUlURk9SIERFTEFZICcwOjA",)), ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")), ("-u --technique=U --fresh-queries --force-partial --dump -T users --dump-format=HTML --answers=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary", "dumped to HTML file")), diff --git a/lib/request/connect.py b/lib/request/connect.py index 8b755a12f..81024f7bb 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -56,12 +56,14 @@ from lib.core.common import safeVariableNaming from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import stdev +from lib.core.common import unArrayizeValue from lib.core.common import unsafeVariableNaming from lib.core.common import urldecode from lib.core.common import urlencode from lib.core.common import wasLastResponseDelayed from lib.core.compat import patchHeaders from lib.core.compat import xrange +from lib.core.convert import encodeBase64 from lib.core.convert import getBytes from lib.core.convert import getText from lib.core.convert import getUnicode @@ -466,7 +468,7 @@ class Connect(object): break if post is not None and not multipart and not getHeader(headers, HTTP_HEADER.CONTENT_TYPE): - headers[HTTP_HEADER.CONTENT_TYPE] = POST_HINT_CONTENT_TYPES.get(kb.postHint, DEFAULT_CONTENT_TYPE) + headers[HTTP_HEADER.CONTENT_TYPE] = POST_HINT_CONTENT_TYPES.get(kb.postHint, DEFAULT_CONTENT_TYPE if unArrayizeValue(conf.base64Parameter) != HTTPMETHOD.POST else PLAIN_TEXT_CONTENT_TYPE) if headers.get(HTTP_HEADER.CONTENT_TYPE) == POST_HINT_CONTENT_TYPES[POST_HINT.MULTIPART]: warnMsg = "missing 'boundary parameter' in '%s' header. " % HTTP_HEADER.CONTENT_TYPE @@ -552,6 +554,13 @@ class Connect(object): else: post = getBytes(post) + if unArrayizeValue(conf.base64Parameter) == HTTPMETHOD.POST: + if kb.place != HTTPMETHOD.POST: + conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) + else: + post = urldecode(post, convall=True) + post = encodeBase64(post) + if target and cmdLineOptions.method or method and method not in (HTTPMETHOD.GET, HTTPMETHOD.POST): req = MethodRequest(url, post, headers) req.set_method(cmdLineOptions.method or method) @@ -976,6 +985,8 @@ class Connect(object): if not place: place = kb.injection.place or PLACE.GET + kb.place = place + if not auxHeaders: auxHeaders = {} @@ -1191,7 +1202,7 @@ class Connect(object): if not token: if conf.csrfUrl and conf.csrfToken and conf.csrfUrl != conf.url and code == _http_client.OK: - if headers and "text/plain" in headers.get(HTTP_HEADER.CONTENT_TYPE, ""): + if headers and PLAIN_TEXT_CONTENT_TYPE in headers.get(HTTP_HEADER.CONTENT_TYPE, ""): token.name = conf.csrfToken token.value = page