diff --git a/lib/core/convert.py b/lib/core/convert.py index a925bba67..bb57e4c18 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -114,7 +114,10 @@ def _serializeEncode(value): name = "%s.%s" % (value.__class__.__module__, value.__class__.__name__) if name in _SERIALIZE_CLASSES: return {_SERIALIZE_TAG: "o", "c": name, "d": [[_serializeEncode(k), _serializeEncode(v)] for (k, v) in value.items()], "s": _serializeEncode(dict(value.__dict__))} - elif value.__class__ is dict: + elif value.__class__ is dict or (name or "").split(".")[0] not in ("lib", "plugins", "thirdparty"): + # a plain dict, or a foreign mapping subclass (e.g. collections.OrderedDict/defaultdict): store the + # items as a plain mapping so the data round-trips, instead of silently degrading to its text repr. + # A non-allowlisted lib/plugins/thirdparty subclass still falls through to _serializeUnknown (fail loudly) return {_SERIALIZE_TAG: "m", "v": [[_serializeEncode(k), _serializeEncode(v)] for (k, v) in value.items()]} else: return _serializeUnknown(value, name) diff --git a/lib/core/settings.py b/lib/core/settings.py index 0df4f9279..d71fcc304 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.124" +VERSION = "1.10.7.125" 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/tests/test_hashdb.py b/tests/test_hashdb.py index 36bbd4dc9..0bc0756f8 100644 --- a/tests/test_hashdb.py +++ b/tests/test_hashdb.py @@ -100,6 +100,19 @@ class TestSerialized(_HashDBCase): self.assertEqual(got.x, 1) self.assertEqual(got.y, [1, 2]) + def test_foreign_mapping_roundtrips_as_dict(self): + # a stdlib dict subclass (e.g. OrderedDict) must round-trip its data rather than + # silently degrade to its text repr (session codec: round-trip or fail loudly) + from collections import OrderedDict + import six + val = OrderedDict([("b", 2), ("a", [1, {"n": "v"}])]) + self.db.write("od", val, True) + self.db.flush() + got = self.db.retrieve("od", True) + self.assertEqual(got, {"b": 2, "a": [1, {"n": "v"}]}) # data preserved (was lost to text repr before) + if six.PY3: + self.assertEqual(list(got), ["b", "a"]) # order preserved where dicts are ordered + def test_bigarray_roundtrip(self): self.db.write("ba", BigArray([1, 2, 3]), True) self.db.flush()