mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-10-12 02:22:55 +00:00
Fixing CI/CD errors
This commit is contained in:
@@ -20,7 +20,7 @@ from lib.core.enums import OS
|
||||
from thirdparty import six
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.10.8.32"
|
||||
VERSION = "1.10.8.33"
|
||||
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)
|
||||
|
||||
@@ -114,6 +114,37 @@ def reset_dbms():
|
||||
kb.dbmsVersion = [UNKNOWN_DBMS_VERSION]
|
||||
|
||||
|
||||
# --- patching shared singletons (agent, unescaper, ...) ---
|
||||
|
||||
_MISSING = object()
|
||||
|
||||
|
||||
def save_attrs(obj, *names):
|
||||
"""Snapshot attributes of a shared singleton so tearDown can restore them EXACTLY.
|
||||
|
||||
agent.payload and friends are methods on the CLASS: patching one sets an *instance* attribute
|
||||
that shadows it, and restoring by assignment leaves that instance attribute behind holding a
|
||||
bound method. Harmless on its own - but invisible state, and a later module whose cleanup keys
|
||||
on "did this attribute exist before me?" then reads True, skips its own del, and leaks its stub
|
||||
into every module that follows (test_techniques + test_checks did exactly that to
|
||||
test_union_engine, whose real payloads silently became the string "PAYLOAD").
|
||||
|
||||
Pair with restore_attrs(); it deletes what was not there before and restores what was.
|
||||
"""
|
||||
|
||||
return [(obj, name, obj.__dict__.get(name, _MISSING)) for name in names]
|
||||
|
||||
|
||||
def restore_attrs(saved):
|
||||
"""Undo save_attrs(), leaving obj.__dict__ exactly as it was found."""
|
||||
|
||||
for obj, name, value in saved:
|
||||
if value is _MISSING:
|
||||
obj.__dict__.pop(name, None)
|
||||
else:
|
||||
setattr(obj, name, value)
|
||||
|
||||
|
||||
# --- property/fuzz testing harness (shared so individual test files don't each reinvent it) ---
|
||||
|
||||
_PROPERTY_BASE = 0x51A1
|
||||
|
||||
+5
-10
@@ -27,7 +27,7 @@ import time
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _testutils import bootstrap
|
||||
from _testutils import bootstrap, save_attrs, restore_attrs
|
||||
bootstrap()
|
||||
|
||||
import lib.controller.checks as checks
|
||||
@@ -88,13 +88,11 @@ class _ChecksTestBase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self._snap = _snapshot()
|
||||
# remember the real seams so monkeypatches can't leak. agent.payload /
|
||||
# addPayloadDelimiters are class methods on a shared singleton: patching
|
||||
# sets an *instance* attribute, so it's restored by deleting that
|
||||
# attribute (reassigning would leave a stale bound method behind).
|
||||
# addPayloadDelimiters are class methods on a shared singleton, so they need
|
||||
# save_attrs()/restore_attrs() rather than a plain reassignment (see _testutils).
|
||||
self._origQueryPage = checks.Request.queryPage
|
||||
self._origGetPage = checks.Request.getPage
|
||||
self._agentHadPayload = "payload" in checks.agent.__dict__
|
||||
self._agentHadAddDelims = "addPayloadDelimiters" in checks.agent.__dict__
|
||||
self._savedAgent = save_attrs(checks.agent, "payload", "addPayloadDelimiters")
|
||||
self._origReadInput = checks.readInput
|
||||
self._origDbmsErr = checks.wasLastResponseDBMSError
|
||||
self._origHttpErr = checks.wasLastResponseHTTPError
|
||||
@@ -111,10 +109,7 @@ class _ChecksTestBase(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
checks.Request.queryPage = self._origQueryPage
|
||||
checks.Request.getPage = self._origGetPage
|
||||
if not self._agentHadPayload and "payload" in checks.agent.__dict__:
|
||||
del checks.agent.payload
|
||||
if not self._agentHadAddDelims and "addPayloadDelimiters" in checks.agent.__dict__:
|
||||
del checks.agent.addPayloadDelimiters
|
||||
restore_attrs(self._savedAgent)
|
||||
checks.readInput = self._origReadInput
|
||||
checks.wasLastResponseDBMSError = self._origDbmsErr
|
||||
checks.wasLastResponseHTTPError = self._origHttpErr
|
||||
|
||||
@@ -38,7 +38,7 @@ import time
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _testutils import bootstrap, set_dbms, reset_dbms
|
||||
from _testutils import bootstrap, set_dbms, reset_dbms, save_attrs, restore_attrs
|
||||
bootstrap()
|
||||
|
||||
from lib.core.agent import agent
|
||||
@@ -131,7 +131,7 @@ class _DnsCase(unittest.TestCase):
|
||||
# (agent.prefixQuery/agent.payload, needing a full kb.injection). That plumbing is
|
||||
# generic - not DNS logic - and the mock oracle ignores the payload, so stub it to a
|
||||
# pass-through; the DNS-specific snippet/substring/chunking still runs for real.
|
||||
self._saved_prefixQuery, self._saved_payload = agent.prefixQuery, agent.payload
|
||||
self._s_agent = save_attrs(agent, "prefixQuery", "payload")
|
||||
agent.prefixQuery = lambda expression, *a, **k: expression
|
||||
agent.payload = lambda place=None, parameter=None, value=None, newValue=None, where=None: newValue or ""
|
||||
set_dbms(self.DBMS_NAME)
|
||||
@@ -148,7 +148,7 @@ class _DnsCase(unittest.TestCase):
|
||||
dnsmod.randomStr = self._saved_randomStr
|
||||
dnstestmod.randomInt = self._saved_randomInt
|
||||
dnsmod.hashDBRetrieve, dnsmod.hashDBWrite = self._saved_hdbR, self._saved_hdbW
|
||||
agent.prefixQuery, agent.payload = self._saved_prefixQuery, self._saved_payload
|
||||
restore_attrs(self._s_agent)
|
||||
|
||||
def _install_oracle(self, secret, working=True, force=None):
|
||||
"""
|
||||
@@ -293,10 +293,12 @@ class TestDnsLabelInvariant(_DnsCase):
|
||||
# "SUBSTRING((...) FROM 1 FOR 13)"; the substring LENGTH argument (the source's real
|
||||
# chunk_length) is the last integer literal in it. Capture it per iteration so the oracle
|
||||
# emits a chunk of exactly that size - the source's arithmetic, not a copy of it.
|
||||
saved_hexConvertField = agent.hexConvertField
|
||||
real_hexConvertField = agent.hexConvertField # the spy delegates to it
|
||||
saved_hexConvertField = save_attrs(agent, "hexConvertField")
|
||||
|
||||
def spy_hexConvertField(field):
|
||||
source_chunk_lengths.append(int(re.findall(r"\d+", field)[-1]))
|
||||
return saved_hexConvertField(field)
|
||||
return real_hexConvertField(field)
|
||||
agent.hexConvertField = spy_hexConvertField
|
||||
|
||||
def oracle(payload=None, *args, **kwargs):
|
||||
@@ -328,7 +330,7 @@ class TestDnsLabelInvariant(_DnsCase):
|
||||
try:
|
||||
result = dnsmod.dnsUse("%s AND %d=%d", "user()")
|
||||
finally:
|
||||
agent.hexConvertField = saved_hexConvertField
|
||||
restore_attrs(saved_hexConvertField)
|
||||
|
||||
# round-trip must still work (the source must actually reassemble what it chunked)
|
||||
self.assertEqual(result, secret)
|
||||
|
||||
@@ -16,7 +16,7 @@ import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _testutils import bootstrap
|
||||
from _testutils import bootstrap, save_attrs, restore_attrs
|
||||
bootstrap()
|
||||
|
||||
from lib.core.settings import (JSON_RECOGNITION_REGEX, JSON_LIKE_RECOGNITION_REGEX,
|
||||
@@ -219,7 +219,7 @@ def _drive_hpp(payload, name="id"):
|
||||
captured["value"] = value
|
||||
raise _Sentinel()
|
||||
|
||||
orig_remove = agent.removePayloadDelimiters
|
||||
saved_remove = save_attrs(agent, "removePayloadDelimiters")
|
||||
agent.removePayloadDelimiters = _capture
|
||||
try:
|
||||
conf.direct = False
|
||||
@@ -238,7 +238,7 @@ def _drive_hpp(payload, name="id"):
|
||||
except _Sentinel:
|
||||
pass
|
||||
finally:
|
||||
agent.removePayloadDelimiters = orig_remove
|
||||
restore_attrs(saved_remove)
|
||||
|
||||
_ = re.escape(PAYLOAD_DELIMITER)
|
||||
return re.search(r"(?s)%s(?P<result>.*?)%s" % (_, _), captured["value"]).group("result")
|
||||
|
||||
@@ -30,7 +30,7 @@ import tempfile
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _testutils import bootstrap, set_dbms, reset_dbms
|
||||
from _testutils import bootstrap, set_dbms, reset_dbms, save_attrs, restore_attrs
|
||||
bootstrap()
|
||||
|
||||
from lib.core.data import conf, kb
|
||||
@@ -94,9 +94,7 @@ class _UnionCase(unittest.TestCase):
|
||||
self._scounters = kb.get("counters")
|
||||
self._sinj_data = kb.injection.data
|
||||
self._shashdb = conf.get("hashDB")
|
||||
self._s_forge = agent.forgeUnionQuery
|
||||
self._s_concat = agent.concatQuery
|
||||
self._s_payload = agent.payload
|
||||
self._s_agent = save_attrs(agent, "forgeUnionQuery", "concatQuery", "payload")
|
||||
self._s_escape = unescaper.escape
|
||||
|
||||
for k, v in _UU_CONF.items():
|
||||
@@ -131,9 +129,7 @@ class _UnionCase(unittest.TestCase):
|
||||
kb.counters = self._scounters
|
||||
kb.injection.data = self._sinj_data
|
||||
conf.hashDB = self._shashdb
|
||||
agent.forgeUnionQuery = self._s_forge
|
||||
agent.concatQuery = self._s_concat
|
||||
agent.payload = self._s_payload
|
||||
restore_attrs(self._s_agent)
|
||||
unescaper.escape = self._s_escape
|
||||
|
||||
def _install_page(self, page):
|
||||
@@ -325,11 +321,8 @@ class _UnionLimitCase(unittest.TestCase):
|
||||
self._sinj_data = kb.injection.data
|
||||
self._shashdb = conf.get("hashDB")
|
||||
self._sbatch = conf.get("batch")
|
||||
self._s_forge = agent.forgeUnionQuery
|
||||
self._s_concat = agent.concatQuery
|
||||
self._s_payload = agent.payload
|
||||
self._s_agent = save_attrs(agent, "forgeUnionQuery", "concatQuery", "payload", "_lastexpr")
|
||||
self._s_escape = unescaper.escape
|
||||
self._s_lastexpr = getattr(agent, "_lastexpr", None)
|
||||
self._s_initTechnique = uu.initTechnique
|
||||
|
||||
for k, v in _UU_CONF_LIMIT.items():
|
||||
@@ -372,11 +365,8 @@ class _UnionLimitCase(unittest.TestCase):
|
||||
kb.counters = self._scounters
|
||||
kb.injection.data = self._sinj_data
|
||||
conf.hashDB = self._shashdb
|
||||
agent.forgeUnionQuery = self._s_forge
|
||||
agent.concatQuery = self._s_concat
|
||||
agent.payload = self._s_payload
|
||||
restore_attrs(self._s_agent)
|
||||
unescaper.escape = self._s_escape
|
||||
agent._lastexpr = self._s_lastexpr
|
||||
uu.initTechnique = self._s_initTechnique
|
||||
|
||||
if self._s_columns is None:
|
||||
@@ -500,10 +490,7 @@ class _ErrorCase(unittest.TestCase):
|
||||
self._shashdb = conf.get("hashDB")
|
||||
self._sbatch = conf.get("batch")
|
||||
|
||||
self._s_prefix = agent.prefixQuery
|
||||
self._s_suffix = agent.suffixQuery
|
||||
self._s_payload = agent.payload
|
||||
self._s_nullcast = agent.nullAndCastField
|
||||
self._s_agent = save_attrs(agent, "prefixQuery", "suffixQuery", "payload", "nullAndCastField")
|
||||
self._s_escape = unescaper.escape
|
||||
|
||||
# restore thread state we touch
|
||||
@@ -557,10 +544,7 @@ class _ErrorCase(unittest.TestCase):
|
||||
kb.injection.data = self._sinj_data
|
||||
conf.hashDB = self._shashdb
|
||||
|
||||
agent.prefixQuery = self._s_prefix
|
||||
agent.suffixQuery = self._s_suffix
|
||||
agent.payload = self._s_payload
|
||||
agent.nullAndCastField = self._s_nullcast
|
||||
restore_attrs(self._s_agent)
|
||||
unescaper.escape = self._s_escape
|
||||
|
||||
td = getCurrentThreadData()
|
||||
|
||||
@@ -26,6 +26,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _testutils import bootstrap, set_dbms, reset_dbms
|
||||
bootstrap()
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.data import conf, kb
|
||||
from lib.core.datatype import AttribDict
|
||||
from lib.core.enums import PAYLOAD, PLACE
|
||||
@@ -74,6 +75,12 @@ class TestOrderByColumnCount(unittest.TestCase):
|
||||
ut.Request.queryPage = self._sqp
|
||||
|
||||
def _detect(self, true_count):
|
||||
# canary: a leaked agent.payload stub (another module patching the shared singleton and
|
||||
# restoring it by assignment) makes every probe below identical, so the ORDER BY oracle turns
|
||||
# unusable and this test used to fail as a bare 'None != 25'. Name the cause instead.
|
||||
self.assertNotIn("payload", agent.__dict__,
|
||||
"agent.payload is stubbed - a test module leaked it (see _testutils.save_attrs)")
|
||||
|
||||
def oracle(payload=None, place=None, content=False, raise404=True, **kwargs):
|
||||
m = re.search(r"ORDER BY (\d+)", payload or "")
|
||||
cols = int(m.group(1)) if m else 1
|
||||
|
||||
Reference in New Issue
Block a user