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
|
from thirdparty import six
|
||||||
|
|
||||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
# 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 = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
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)
|
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]
|
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/fuzz testing harness (shared so individual test files don't each reinvent it) ---
|
||||||
|
|
||||||
_PROPERTY_BASE = 0x51A1
|
_PROPERTY_BASE = 0x51A1
|
||||||
|
|||||||
+5
-10
@@ -27,7 +27,7 @@ import time
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
from _testutils import bootstrap
|
from _testutils import bootstrap, save_attrs, restore_attrs
|
||||||
bootstrap()
|
bootstrap()
|
||||||
|
|
||||||
import lib.controller.checks as checks
|
import lib.controller.checks as checks
|
||||||
@@ -88,13 +88,11 @@ class _ChecksTestBase(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self._snap = _snapshot()
|
self._snap = _snapshot()
|
||||||
# remember the real seams so monkeypatches can't leak. agent.payload /
|
# remember the real seams so monkeypatches can't leak. agent.payload /
|
||||||
# addPayloadDelimiters are class methods on a shared singleton: patching
|
# addPayloadDelimiters are class methods on a shared singleton, so they need
|
||||||
# sets an *instance* attribute, so it's restored by deleting that
|
# save_attrs()/restore_attrs() rather than a plain reassignment (see _testutils).
|
||||||
# attribute (reassigning would leave a stale bound method behind).
|
|
||||||
self._origQueryPage = checks.Request.queryPage
|
self._origQueryPage = checks.Request.queryPage
|
||||||
self._origGetPage = checks.Request.getPage
|
self._origGetPage = checks.Request.getPage
|
||||||
self._agentHadPayload = "payload" in checks.agent.__dict__
|
self._savedAgent = save_attrs(checks.agent, "payload", "addPayloadDelimiters")
|
||||||
self._agentHadAddDelims = "addPayloadDelimiters" in checks.agent.__dict__
|
|
||||||
self._origReadInput = checks.readInput
|
self._origReadInput = checks.readInput
|
||||||
self._origDbmsErr = checks.wasLastResponseDBMSError
|
self._origDbmsErr = checks.wasLastResponseDBMSError
|
||||||
self._origHttpErr = checks.wasLastResponseHTTPError
|
self._origHttpErr = checks.wasLastResponseHTTPError
|
||||||
@@ -111,10 +109,7 @@ class _ChecksTestBase(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
checks.Request.queryPage = self._origQueryPage
|
checks.Request.queryPage = self._origQueryPage
|
||||||
checks.Request.getPage = self._origGetPage
|
checks.Request.getPage = self._origGetPage
|
||||||
if not self._agentHadPayload and "payload" in checks.agent.__dict__:
|
restore_attrs(self._savedAgent)
|
||||||
del checks.agent.payload
|
|
||||||
if not self._agentHadAddDelims and "addPayloadDelimiters" in checks.agent.__dict__:
|
|
||||||
del checks.agent.addPayloadDelimiters
|
|
||||||
checks.readInput = self._origReadInput
|
checks.readInput = self._origReadInput
|
||||||
checks.wasLastResponseDBMSError = self._origDbmsErr
|
checks.wasLastResponseDBMSError = self._origDbmsErr
|
||||||
checks.wasLastResponseHTTPError = self._origHttpErr
|
checks.wasLastResponseHTTPError = self._origHttpErr
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import time
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
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()
|
bootstrap()
|
||||||
|
|
||||||
from lib.core.agent import agent
|
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
|
# (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
|
# 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.
|
# 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.prefixQuery = lambda expression, *a, **k: expression
|
||||||
agent.payload = lambda place=None, parameter=None, value=None, newValue=None, where=None: newValue or ""
|
agent.payload = lambda place=None, parameter=None, value=None, newValue=None, where=None: newValue or ""
|
||||||
set_dbms(self.DBMS_NAME)
|
set_dbms(self.DBMS_NAME)
|
||||||
@@ -148,7 +148,7 @@ class _DnsCase(unittest.TestCase):
|
|||||||
dnsmod.randomStr = self._saved_randomStr
|
dnsmod.randomStr = self._saved_randomStr
|
||||||
dnstestmod.randomInt = self._saved_randomInt
|
dnstestmod.randomInt = self._saved_randomInt
|
||||||
dnsmod.hashDBRetrieve, dnsmod.hashDBWrite = self._saved_hdbR, self._saved_hdbW
|
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):
|
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
|
# "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
|
# 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.
|
# 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):
|
def spy_hexConvertField(field):
|
||||||
source_chunk_lengths.append(int(re.findall(r"\d+", field)[-1]))
|
source_chunk_lengths.append(int(re.findall(r"\d+", field)[-1]))
|
||||||
return saved_hexConvertField(field)
|
return real_hexConvertField(field)
|
||||||
agent.hexConvertField = spy_hexConvertField
|
agent.hexConvertField = spy_hexConvertField
|
||||||
|
|
||||||
def oracle(payload=None, *args, **kwargs):
|
def oracle(payload=None, *args, **kwargs):
|
||||||
@@ -328,7 +330,7 @@ class TestDnsLabelInvariant(_DnsCase):
|
|||||||
try:
|
try:
|
||||||
result = dnsmod.dnsUse("%s AND %d=%d", "user()")
|
result = dnsmod.dnsUse("%s AND %d=%d", "user()")
|
||||||
finally:
|
finally:
|
||||||
agent.hexConvertField = saved_hexConvertField
|
restore_attrs(saved_hexConvertField)
|
||||||
|
|
||||||
# round-trip must still work (the source must actually reassemble what it chunked)
|
# round-trip must still work (the source must actually reassemble what it chunked)
|
||||||
self.assertEqual(result, secret)
|
self.assertEqual(result, secret)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import sys
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
from _testutils import bootstrap
|
from _testutils import bootstrap, save_attrs, restore_attrs
|
||||||
bootstrap()
|
bootstrap()
|
||||||
|
|
||||||
from lib.core.settings import (JSON_RECOGNITION_REGEX, JSON_LIKE_RECOGNITION_REGEX,
|
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
|
captured["value"] = value
|
||||||
raise _Sentinel()
|
raise _Sentinel()
|
||||||
|
|
||||||
orig_remove = agent.removePayloadDelimiters
|
saved_remove = save_attrs(agent, "removePayloadDelimiters")
|
||||||
agent.removePayloadDelimiters = _capture
|
agent.removePayloadDelimiters = _capture
|
||||||
try:
|
try:
|
||||||
conf.direct = False
|
conf.direct = False
|
||||||
@@ -238,7 +238,7 @@ def _drive_hpp(payload, name="id"):
|
|||||||
except _Sentinel:
|
except _Sentinel:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
agent.removePayloadDelimiters = orig_remove
|
restore_attrs(saved_remove)
|
||||||
|
|
||||||
_ = re.escape(PAYLOAD_DELIMITER)
|
_ = re.escape(PAYLOAD_DELIMITER)
|
||||||
return re.search(r"(?s)%s(?P<result>.*?)%s" % (_, _), captured["value"]).group("result")
|
return re.search(r"(?s)%s(?P<result>.*?)%s" % (_, _), captured["value"]).group("result")
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import tempfile
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
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()
|
bootstrap()
|
||||||
|
|
||||||
from lib.core.data import conf, kb
|
from lib.core.data import conf, kb
|
||||||
@@ -94,9 +94,7 @@ class _UnionCase(unittest.TestCase):
|
|||||||
self._scounters = kb.get("counters")
|
self._scounters = kb.get("counters")
|
||||||
self._sinj_data = kb.injection.data
|
self._sinj_data = kb.injection.data
|
||||||
self._shashdb = conf.get("hashDB")
|
self._shashdb = conf.get("hashDB")
|
||||||
self._s_forge = agent.forgeUnionQuery
|
self._s_agent = save_attrs(agent, "forgeUnionQuery", "concatQuery", "payload")
|
||||||
self._s_concat = agent.concatQuery
|
|
||||||
self._s_payload = agent.payload
|
|
||||||
self._s_escape = unescaper.escape
|
self._s_escape = unescaper.escape
|
||||||
|
|
||||||
for k, v in _UU_CONF.items():
|
for k, v in _UU_CONF.items():
|
||||||
@@ -131,9 +129,7 @@ class _UnionCase(unittest.TestCase):
|
|||||||
kb.counters = self._scounters
|
kb.counters = self._scounters
|
||||||
kb.injection.data = self._sinj_data
|
kb.injection.data = self._sinj_data
|
||||||
conf.hashDB = self._shashdb
|
conf.hashDB = self._shashdb
|
||||||
agent.forgeUnionQuery = self._s_forge
|
restore_attrs(self._s_agent)
|
||||||
agent.concatQuery = self._s_concat
|
|
||||||
agent.payload = self._s_payload
|
|
||||||
unescaper.escape = self._s_escape
|
unescaper.escape = self._s_escape
|
||||||
|
|
||||||
def _install_page(self, page):
|
def _install_page(self, page):
|
||||||
@@ -325,11 +321,8 @@ class _UnionLimitCase(unittest.TestCase):
|
|||||||
self._sinj_data = kb.injection.data
|
self._sinj_data = kb.injection.data
|
||||||
self._shashdb = conf.get("hashDB")
|
self._shashdb = conf.get("hashDB")
|
||||||
self._sbatch = conf.get("batch")
|
self._sbatch = conf.get("batch")
|
||||||
self._s_forge = agent.forgeUnionQuery
|
self._s_agent = save_attrs(agent, "forgeUnionQuery", "concatQuery", "payload", "_lastexpr")
|
||||||
self._s_concat = agent.concatQuery
|
|
||||||
self._s_payload = agent.payload
|
|
||||||
self._s_escape = unescaper.escape
|
self._s_escape = unescaper.escape
|
||||||
self._s_lastexpr = getattr(agent, "_lastexpr", None)
|
|
||||||
self._s_initTechnique = uu.initTechnique
|
self._s_initTechnique = uu.initTechnique
|
||||||
|
|
||||||
for k, v in _UU_CONF_LIMIT.items():
|
for k, v in _UU_CONF_LIMIT.items():
|
||||||
@@ -372,11 +365,8 @@ class _UnionLimitCase(unittest.TestCase):
|
|||||||
kb.counters = self._scounters
|
kb.counters = self._scounters
|
||||||
kb.injection.data = self._sinj_data
|
kb.injection.data = self._sinj_data
|
||||||
conf.hashDB = self._shashdb
|
conf.hashDB = self._shashdb
|
||||||
agent.forgeUnionQuery = self._s_forge
|
restore_attrs(self._s_agent)
|
||||||
agent.concatQuery = self._s_concat
|
|
||||||
agent.payload = self._s_payload
|
|
||||||
unescaper.escape = self._s_escape
|
unescaper.escape = self._s_escape
|
||||||
agent._lastexpr = self._s_lastexpr
|
|
||||||
uu.initTechnique = self._s_initTechnique
|
uu.initTechnique = self._s_initTechnique
|
||||||
|
|
||||||
if self._s_columns is None:
|
if self._s_columns is None:
|
||||||
@@ -500,10 +490,7 @@ class _ErrorCase(unittest.TestCase):
|
|||||||
self._shashdb = conf.get("hashDB")
|
self._shashdb = conf.get("hashDB")
|
||||||
self._sbatch = conf.get("batch")
|
self._sbatch = conf.get("batch")
|
||||||
|
|
||||||
self._s_prefix = agent.prefixQuery
|
self._s_agent = save_attrs(agent, "prefixQuery", "suffixQuery", "payload", "nullAndCastField")
|
||||||
self._s_suffix = agent.suffixQuery
|
|
||||||
self._s_payload = agent.payload
|
|
||||||
self._s_nullcast = agent.nullAndCastField
|
|
||||||
self._s_escape = unescaper.escape
|
self._s_escape = unescaper.escape
|
||||||
|
|
||||||
# restore thread state we touch
|
# restore thread state we touch
|
||||||
@@ -557,10 +544,7 @@ class _ErrorCase(unittest.TestCase):
|
|||||||
kb.injection.data = self._sinj_data
|
kb.injection.data = self._sinj_data
|
||||||
conf.hashDB = self._shashdb
|
conf.hashDB = self._shashdb
|
||||||
|
|
||||||
agent.prefixQuery = self._s_prefix
|
restore_attrs(self._s_agent)
|
||||||
agent.suffixQuery = self._s_suffix
|
|
||||||
agent.payload = self._s_payload
|
|
||||||
agent.nullAndCastField = self._s_nullcast
|
|
||||||
unescaper.escape = self._s_escape
|
unescaper.escape = self._s_escape
|
||||||
|
|
||||||
td = getCurrentThreadData()
|
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
|
from _testutils import bootstrap, set_dbms, reset_dbms
|
||||||
bootstrap()
|
bootstrap()
|
||||||
|
|
||||||
|
from lib.core.agent import agent
|
||||||
from lib.core.data import conf, kb
|
from lib.core.data import conf, kb
|
||||||
from lib.core.datatype import AttribDict
|
from lib.core.datatype import AttribDict
|
||||||
from lib.core.enums import PAYLOAD, PLACE
|
from lib.core.enums import PAYLOAD, PLACE
|
||||||
@@ -74,6 +75,12 @@ class TestOrderByColumnCount(unittest.TestCase):
|
|||||||
ut.Request.queryPage = self._sqp
|
ut.Request.queryPage = self._sqp
|
||||||
|
|
||||||
def _detect(self, true_count):
|
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):
|
def oracle(payload=None, place=None, content=False, raise404=True, **kwargs):
|
||||||
m = re.search(r"ORDER BY (\d+)", payload or "")
|
m = re.search(r"ORDER BY (\d+)", payload or "")
|
||||||
cols = int(m.group(1)) if m else 1
|
cols = int(m.group(1)) if m else 1
|
||||||
|
|||||||
Reference in New Issue
Block a user