Fixes version comparison

This commit is contained in:
Miroslav Štampar 2026-07-19 13:37:42 +02:00
parent d08e992ad6
commit 932a5bd7b2
3 changed files with 66 additions and 26 deletions

View file

@ -190,7 +190,6 @@ from lib.core.settings import URI_QUESTION_MARKER
from lib.core.settings import URLENCODE_CHAR_LIMIT
from lib.core.settings import URLENCODE_FAILSAFE_CHARS
from lib.core.settings import USER_AGENT_ALIASES
from lib.core.settings import VERSION_COMPARISON_CORRECTION
from lib.core.settings import VERSION_STRING
from lib.core.settings import ZIP_HEADER
from lib.core.settings import WEBSCARAB_SPLITTER
@ -3500,42 +3499,40 @@ def isDBMSVersionAtLeast(minimum):
if not any(isNoneValue(_) for _ in (Backend.getVersion(), minimum)) and Backend.getVersion() != UNKNOWN_DBMS_VERSION:
version = Backend.getVersion().replace(" ", "").rstrip('.')
correction = 0.0
# Note: a fuzzy/ranged detected version (e.g. '>2', '<2') is captured as a sign so an
# otherwise-equal comparison still resolves in the right direction
vSign = 0
if ">=" in version:
pass
elif '>' in version:
correction = VERSION_COMPARISON_CORRECTION
vSign = 1
elif '<' in version:
correction = -VERSION_COMPARISON_CORRECTION
vSign = -1
version = extractRegexResult(r"(?P<result>[0-9][0-9.]*)", version)
if version:
if '.' in version:
parts = version.split('.', 1)
parts[1] = filterStringValue(parts[1], '[0-9]')
version = '.'.join(parts)
minimum = minimum if isinstance(minimum, six.string_types) else getUnicode(minimum)
try:
version = float(filterStringValue(version, '[0-9.]')) + correction
except ValueError:
return None
mSign = 0
if minimum.startswith(">="):
pass
elif minimum.startswith(">"):
mSign = 1
if isinstance(minimum, six.string_types):
if '.' in minimum:
parts = minimum.split('.', 1)
parts[1] = filterStringValue(parts[1], '[0-9]')
minimum = '.'.join(parts)
minimum = extractRegexResult(r"(?P<result>[0-9][0-9.]*)", minimum)
correction = 0.0
if minimum.startswith(">="):
pass
elif minimum.startswith(">"):
correction = VERSION_COMPARISON_CORRECTION
if minimum:
# Note: compare dotted versions component-wise as int tuples, not as floats; a float
# collapses e.g. 5.4.3->5.43 and 5.10.0->5.100(==5.1), silently mis-ordering multi-part
# or multi-digit-minor versions (MariaDB 10.11, PostgreSQL 9.10, Presto 0.99 vs 0.178)
vParts = tuple(int(_) for _ in re.findall(r"\d+", version))
mParts = tuple(int(_) for _ in re.findall(r"\d+", minimum))
length = max(len(vParts), len(mParts))
vParts += (0,) * (length - len(vParts))
mParts += (0,) * (length - len(mParts))
minimum = float(filterStringValue(minimum, '[0-9.]')) + correction
retVal = version >= minimum
retVal = (vParts, vSign) >= (mParts, mSign)
return retVal

View file

@ -20,7 +20,7 @@ from lib.core.enums import OS
from thirdparty import six
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.10.7.126"
VERSION = "1.10.7.127"
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)

View file

@ -86,6 +86,7 @@ from lib.core.common import (
getTechnique,
getText,
intersect,
isDBMSVersionAtLeast,
isListLike,
isNoneValue,
isNullValue,
@ -983,6 +984,48 @@ class TestAliasToDbmsEnum(unittest.TestCase):
self.assertIsNone(aliasToDbmsEnum(""))
class TestIsDBMSVersionAtLeast(unittest.TestCase):
"""Version gating drives per-DBMS query selection; comparison must be component-wise."""
def setUp(self):
self._saved = kb.get("dbmsVersion")
def tearDown(self):
kb.dbmsVersion = self._saved
def _at_least(self, version, minimum):
kb.dbmsVersion = version
return isDBMSVersionAtLeast(minimum)
def test_single_major_thresholds(self):
self.assertTrue(self._at_least("5.4.3", "5"))
self.assertTrue(self._at_least("8.0.32", "8"))
self.assertFalse(self._at_least("5.7.44", "8"))
def test_multi_digit_minor_ordering(self):
# floats mis-sorted these (10.11->10.11 vs 10.5->10.5): component-wise fixes it
self.assertTrue(self._at_least("10.11", "10.5")) # MariaDB
self.assertFalse(self._at_least("10.6", "10.11"))
self.assertTrue(self._at_least("5.10.0", "5.5"))
self.assertTrue(self._at_least("9.10", "9.6")) # PostgreSQL
def test_presto_sequential_minor(self):
# Presto 0.NNN: release 99 is OLDER than release 178 (float made 0.99 > 0.178)
self.assertFalse(self._at_least("0.99", "0.178"))
self.assertTrue(self._at_least("0.180", "0.178"))
def test_range_and_prefix_semantics(self):
self.assertTrue(self._at_least("2", ">=2.0"))
self.assertFalse(self._at_least("2", ">2"))
self.assertFalse(self._at_least("<2", "2"))
self.assertTrue(self._at_least("<2", "1.5"))
def test_unknown_version_is_none(self):
from lib.core.settings import UNKNOWN_DBMS_VERSION
kb.dbmsVersion = UNKNOWN_DBMS_VERSION
self.assertIsNone(isDBMSVersionAtLeast("5"))
class TestGetPageWordSet(unittest.TestCase):
def test_word_extraction(self):
words = getPageWordSet(u"<html><title>foobar</title><body>test</body></html>")