From 6369a38ebc2f20cfc51c469897b1b81647906093 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 26 Feb 2014 08:56:17 +0100 Subject: [PATCH] Adding support for JSON-like data with single quote --- lib/core/agent.py | 4 ++++ lib/core/dicts.py | 1 + lib/core/enums.py | 1 + lib/core/settings.py | 3 +++ lib/core/target.py | 13 +++++++++++++ lib/request/connect.py | 5 +++++ 6 files changed, 27 insertions(+) diff --git a/lib/core/agent.py b/lib/core/agent.py index 255b9bc85..d34a40d2c 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -100,6 +100,8 @@ class Agent(object): origValue = origValue.split('>')[-1] elif kb.postHint == POST_HINT.JSON: origValue = extractRegexResult(r"(?s)\"\s*:\s*(?P\d+\Z)", origValue) or extractRegexResult(r'(?s)(?P[^"]+\Z)', origValue) + elif kb.postHint == POST_HINT.JSON_LIKE: + origValue = extractRegexResult(r'(?s)\'\s*:\s*(?P\d+\Z)', origValue) or extractRegexResult(r"(?s)(?P[^']+\Z)", origValue) else: _ = extractRegexResult(r"(?s)(?P[^\s<>{}();'\"]+\Z)", origValue) or "" origValue = _.split('=', 1)[1] if '=' in _ else "" @@ -142,6 +144,8 @@ class Agent(object): _ = "%s%s" % (origValue, CUSTOM_INJECTION_MARK_CHAR) if kb.postHint == POST_HINT.JSON and not isNumber(newValue) and not '"%s"' % _ in paramString: newValue = '"%s"' % newValue + elif kb.postHint == POST_HINT.JSON_LIKE and not isNumber(newValue) and not "'%s'" % _ in paramString: + newValue = "'%s'" % newValue newValue = newValue.replace(CUSTOM_INJECTION_MARK_CHAR, REPLACEMENT_MARKER) retVal = paramString.replace(_, self.addPayloadDelimiters(newValue)) retVal = retVal.replace(CUSTOM_INJECTION_MARK_CHAR, "").replace(REPLACEMENT_MARKER, CUSTOM_INJECTION_MARK_CHAR) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index a720bf51d..0641f22c2 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -203,6 +203,7 @@ SQL_STATEMENTS = { POST_HINT_CONTENT_TYPES = { POST_HINT.JSON: "application/json", + POST_HINT.JSON_LIKE: "application/json", POST_HINT.MULTIPART: "multipart/form-data", POST_HINT.SOAP: "application/soap+xml", POST_HINT.XML: "application/xml", diff --git a/lib/core/enums.py b/lib/core/enums.py index bf3785197..53fce1aff 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -71,6 +71,7 @@ class PLACE: class POST_HINT: SOAP = "SOAP" JSON = "JSON" + JSON_LIKE = "JSON-like" MULTIPART = "MULTIPART" XML = "XML (generic)" diff --git a/lib/core/settings.py b/lib/core/settings.py index fb5a513b6..51c7e1e19 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -541,6 +541,9 @@ SOAP_RECOGNITION_REGEX = r"(?s)\A(<\?xml[^>]+>)?\s*<([^> ]+)( [^>]+)?>.+\ # Regular expression used for detecting JSON POST data JSON_RECOGNITION_REGEX = r'(?s)\A(\s*\[)*\s*\{.*"[^"]+"\s*:\s*("[^"]+"|\d+).*\}\s*(\]\s*)*\Z' +# Regular expression used for detecting JSON-like POST data +JSON_LIKE_RECOGNITION_REGEX = r"(?s)\A(\s*\[)*\s*\{.*'[^']+'\s*:\s*('[^']+'|\d+).*\}\s*(\]\s*)*\Z" + # Regular expression used for detecting multipart POST data MULTIPART_RECOGNITION_REGEX = r"(?i)Content-Disposition:[^;]+;\s*name=" diff --git a/lib/core/target.py b/lib/core/target.py index 6d111c296..997111aac 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -44,6 +44,7 @@ from lib.core.settings import ASTERISK_MARKER from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR from lib.core.settings import HOST_ALIASES from lib.core.settings import JSON_RECOGNITION_REGEX +from lib.core.settings import JSON_LIKE_RECOGNITION_REGEX from lib.core.settings import MULTIPART_RECOGNITION_REGEX from lib.core.settings import PROBLEMATIC_CUSTOM_INJECTION_PATTERNS from lib.core.settings import REFERER_ALIASES @@ -125,6 +126,18 @@ def _setRequestParams(): conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.JSON + elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): + message = "JSON-like data found in %s data. " % conf.method + message += "Do you want to process it? [Y/n/q] " + test = readInput(message, default="Y") + if test and test[0] in ("q", "Q"): + raise SqlmapUserQuitException + elif test[0] not in ("n", "N"): + conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) + conf.data = re.sub(r"('(?P[^']+)'\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % CUSTOM_INJECTION_MARK_CHAR), conf.data) + conf.data = re.sub(r"('(?P[^']+)'\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % CUSTOM_INJECTION_MARK_CHAR), conf.data) + kb.postHint = POST_HINT.JSON_LIKE + elif re.search(SOAP_RECOGNITION_REGEX, conf.data): message = "SOAP/XML data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " diff --git a/lib/request/connect.py b/lib/request/connect.py index 97afafba5..cdf929d2c 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -658,6 +658,11 @@ class Connect(object): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] + elif kb.postHint == POST_HINT.JSON_LIKE: + if payload.startswith("'") and payload.endswith("'"): + payload = json.dumps(payload[1:-1]) + else: + payload = json.dumps(payload)[1:-1] value = agent.replacePayload(value, payload) else: # GET, POST, URI and Cookie payload needs to be throughly URL encoded