diff --git a/lib/core/settings.py b/lib/core/settings.py index c0bb332ee..332d349e6 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.7.73" +VERSION = "1.10.7.74" 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/techniques/union/test.py b/lib/techniques/union/test.py index 5c2022c3a..fd0b6bd83 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -61,14 +61,37 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where= @stackedmethod def _orderByTechnique(lowerCount=None, upperCount=None): - def _orderByTest(cols): + def _orderByProbe(cols): query = agent.prefixQuery("ORDER BY %d" % cols, prefix=prefix) query = agent.suffixQuery(query, suffix=suffix, comment=comment) payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where) page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False) - return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order (by|clause)", "unknown column", "failed")) and not kb.heavilyDynamic and comparison(page, headers, code) or re.search(r"data types cannot be compared or sorted", page or "", re.I) is not None + errored = any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order (by|clause)", "unknown column", "failed")) + return page, headers, code, errored - if _orderByTest(1 if lowerCount is None else lowerCount) and not _orderByTest(randomInt() if upperCount is None else upperCount + 1): + lowCount = 1 if lowerCount is None else lowerCount + highCount = randomInt() if upperCount is None else upperCount + 1 + + lowPage, lowHeaders, lowCode, lowErrored = _orderByProbe(lowCount) + highPage, highHeaders, highCode, highErrored = _orderByProbe(highCount) + + # When an out-of-range ORDER BY position visibly errors on this target, the column count can be + # bisected on error presence alone - immune to result-set shifts caused by the injection context + # (e.g. a LIKE '%...%' search whose matches change once the string literal is closed), which would + # otherwise make the response-similarity oracle reject a still-valid position. + errorOracle = highErrored and not lowErrored + + def _orderByValid(page, headers, code, errored): + if re.search(r"data types cannot be compared or sorted", page or "", re.I): + return True + if errored: + return False + return errorOracle or (not kb.heavilyDynamic and comparison(page, headers, code)) + + def _orderByTest(cols): + return _orderByValid(*_orderByProbe(cols)) + + if _orderByValid(lowPage, lowHeaders, lowCode, lowErrored) and not _orderByValid(highPage, highHeaders, highCode, highErrored): infoMsg = "'ORDER BY' technique appears to be usable. " infoMsg += "This should reduce the time needed " infoMsg += "to find the right number "