Some more stabilization of unittests
Some checks are pending
/ build (macos-latest, 3.8) (push) Waiting to run
/ build (ubuntu-latest, pypy-2.7) (push) Waiting to run
/ build (windows-latest, 3.14) (push) Waiting to run

This commit is contained in:
Miroslav Štampar 2026-07-02 22:52:02 +02:00
parent 71d9c6d0f4
commit d60e95ede7
20 changed files with 122 additions and 33 deletions

View file

@ -168,7 +168,7 @@ d69e84f1648cdb907f5d2dd454f03874a4613752b07867510145d51d84b3c56f lib/controller
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/controller/__init__.py
48ffe93d61734e16c3b20153b51595853d9ac1fbcf0b537e0e61e957b0c0bfa6 lib/core/agent.py
c51c33501cc905586a9aaac93b06f2ac6f71628d032a7dc39fd0ef05d7ee3856 lib/core/bigarray.py
e6866a8a8870c345334296e9533042719d32219127fafdda481566b119c3a50d lib/core/common.py
c230a214023a6556648e6af485b42fbcd10f23d2cb9018ad7bc68e36f7241328 lib/core/common.py
8f1272487e1adfcc8c755a2f56f0c6d21eac5e685a73a9a159482f9dc9142bc5 lib/core/compat.py
5301ba2204404d086e9a67271cde00fc10214c63b018a95fc5aa90ff9e0b2ad9 lib/core/convert.py
c03dc585f89642cfd81b087ac2723e3e1bb3bfa8c60e6f5fe58ef3b0113ebfe6 lib/core/data.py
@ -189,7 +189,7 @@ c2db614a3ce7dda889152bea8bd6d709e5d8c2b556741fdbfe44469f27ce266b lib/core/enums
9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
de1ffd738b35e31eb95467eda8a230cc81ff4d21e48e4c02c29da09299823126 lib/core/settings.py
2f2411c91cab0ee8b337c9672bd510e408e1ab44b83ec0eaf0763604f4f99926 lib/core/settings.py
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
15d36cdac9389d0a54a6c33fbb89f32bb65e303f50de573773dcb6d4618bca64 lib/core/target.py
@ -201,7 +201,7 @@ b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unesc
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/__init__.py
54bfd31ebded3ffa5848df1c644f196eb704116517c7a3d860b5d081e984d821 lib/parse/banner.py
fef119c6f3f2fe6a092112fd832d645c58e4c3c2af0bd97ace4487372c1e3574 lib/parse/cmdline.py
02d82e4069bd98c52755417f8b8e306d79945672656ac24f1a45e7a6eff4b158 lib/parse/configfile.py
925a068efa1885fa40671414a887c088f2aafbe8cb76f01286e6bde3f624dac1 lib/parse/configfile.py
c5b258be7485089fac9d9cd179960e774fbd85e62836dc67cce76cc028bb6aeb lib/parse/handler.py
5c9a9caee948843d5537745640cc7b98d70a0412cc0949f59d4ebe8b2907c06c lib/parse/headers.py
ea9b195e5f5030b96d1993c106c1e13fb5c7faaf6bdc5daacfd06ec984e7f323 lib/parse/html.py
@ -264,7 +264,7 @@ bd9267d94390ba87d6c5a35c90f2406d6a4135a7c8ea01db76dd9e6519eee2ed lib/utils/dial
3c4ad819589fe4fca303706dc87969273a07a04dee85e23f064b39caf1fb80e9 lib/utils/gui.py
972c5db9c9e30ac0f91c0f8d4df4531d0304e151dac99f1399c37c952ba9f935 lib/utils/har.py
0cd3860c03e39bacd1d0fe4cf1a0c605de48ff82f70441319f21d47e38e7e3a9 lib/utils/hashdb.py
f1f29dee813d08be77023543c45a4f3621ed26b1bbc133c020b618256663baaf lib/utils/hash.py
0c4ffffbf873bfc6981da6c92697331ce8d985025982ad7c6d52f2c26639df73 lib/utils/hash.py
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/utils/__init__.py
1bbf57e43f921d4132e6e5a336ff39454a9506b36de94ebcc45879d0abcac56a lib/utils/keysetdump.py
b57aa20b7a6fd8afd07bae773fd03f8acb05655ee605362b220e65a0664dc38d lib/utils/library.py
@ -587,14 +587,14 @@ dcdeed9ee285e63cf06baf8347e3db7f210ef25a63869bab78ce1ec6898ae191 tamper/unional
ce1b6bf8f296de27014d6f21aa8b3df9469d418740cd31c93d1f5e36d6c509cf tamper/xforwardedfor.py
44401cad3e39ae9fb899ed5d0e2fdd0879561de05c3117f17f3b0db54f4e3724 tests/__init__.py
0e9054da5d1fed1ddfc982b8f559914237f65d9be5e595c3218fcd236dfa7212 tests/test_agent.py
138381e05a860272fedab780e6c38ab74c59c879048b11b909d23f8df654352a tests/test_api.py
feb763ddcbf4f32822372ca53f8c71c754af7b72510ef06e1e9c77927fc90b10 tests/test_bigarray.py
9dc0ce7a038e7ac67c7f992b478a58492dad335d14761fa0600eec1f5a339c76 tests/test_api.py
694d8c87b2b98d7de6bc09fd634a2d32c436c7955c793cca6fa8790d3868f701 tests/test_bigarray.py
aeefe699f477e77ec4fb46c2692a1ea04cd89ad9cce62e8857d13e3bc0606e9d tests/test_brute.py
27ad87c0ea377e0657bd6f6a4eaa0e9756aa9d28ec0483bdadeb3f66dcc4660d tests/test_charset.py
7596fc69678304923b5c945c0fd9b8ee62a2dfc7fb14ccb6dc7af30893dc8012 tests/test_checks.py
9cc73e06ba3b4c07e0d8f5fd1962f8f25ba6b7ab7278cfb094bfff76fe5e7328 tests/test_checks.py
9e678a56e16211c49ab4995b6c658d3f122bfa3b357d9e17ff38f5a489ace6ad tests/test_cloak.py
2ec894f49ca9bd750a23ead16dae176bcbc57d18ec5847fa4a5eeb886d75c1bd tests/test_common_helpers.py
d436ad4c99be71d5faadb37f63d96a498e7e2b84f257ac9c7965b2ccd999e9e9 tests/test_common.py
886754f39804a4f3f7157124b21ce08d9bad83d156dcd81bc942521bb42c4a29 tests/test_common.py
899bc085e96d68f8a8cbe0d7e55863e98ef37b73ab0e4234f7d969e31ea2d23a tests/test_comparison_json.py
7b72d4f850bbd059b8e95fceb45a58470354cb7270c99b0e9981aaa189af20d1 tests/test_comparison.py
a7c3cf9f7820f377ebfdecf9383ebebc2932dd4a2a531a2b4496071f9d973c1c tests/test_compat.py
@ -615,7 +615,7 @@ ec58ba0849d90d2bb7580fe2b8b96cd8299ddfc25f14dc27d9de9d41f152c78a tests/test_dns
2bbe4b01f79992cfa8884651fc0a28dbd0e3abb0cbea9eb7eadf1f98ca3c3420 tests/test_encoding.py
f4c54b19a294bf392b23dc627781d50894c8e44ca4fe5d7315c98984a3e196a4 tests/test_entries.py
ed7df24ce154e4cbb4462874a38202794664d12b083845bbee9f80481ec9cf52 tests/test_error_engine.py
6f3c214128c7147307c70f0905a0d1aa8118cbbc95086c6fcadce13009fb4946 tests/test_filesystem.py
950527f0abaffdc031e34336a870cd0f89723ee8589bf77763f5978f5e4c0be8 tests/test_filesystem.py
31fa778c7ee318169961d04ea7b93afc539c24b4114a6a3eaf45698fef57bb4b tests/test_fingerprint.py
abb6eef3d2d08b87b6210dde6dd1333d39da64f5abe5574240fa47efce7528f3 tests/test_generic_takeover.py
b7d59fe68af29d47dda1d7ad77e9b5c91ed50e9efbb976e62e0dc67dd11b3e17 tests/test_graphql.py
@ -627,36 +627,36 @@ c04e8358fb6df45f69f2f26435c971acde280535bf304e84d30cf2681158c6a7 tests/test_has
b23bf934dafe54c241761517a7b8c139159aa4b941db10832a626a51fea81e35 tests/test_http2.py
139dcedb9093eb0404ce497549eb6ab7e83ae1e70df8eb42da74ab5a3e7d2a85 tests/test_identifiers_output.py
0a5736b86a47e66d47d44ecf7b8c7531417453fc3e976cd64e9865d3afba78f4 tests/test_inference_engine.py
0fc7bd9bae4fbd09f51027780b7a8e72eab73810dccdfdf87ed9e489e6e671c9 tests/test_ldap.py
22629df783f75a88c2a30ffb8e37af095e761b771322fefbd69bdd7a5c9348fb tests/test_ldap.py
571d7761d60a2919985d065893af68eac5d12286f491eaba434c1d8587f913a0 tests/test_library.py
d2f701f4c3a8621b937ddd322343df91e102af5424ab58675dec4dc7781035b4 tests/test_misc.py
790b78c600b61eb0bdd6e07e14b1db3eb2ddd5fc5d4edb9e975f85ced38558c7 tests/test_nosql.py
2f6d2270b26f68b3c9b511364c57eb5eb7b010ff716346fe2b320df30280f94c tests/test_nosql.py
88a8c7ce0ba0ca721dffbcf9351cd07f7e471ad2fe667a10608c18952b09868d tests/test_openapi_drift.py
a0d173bb595ffbd2b49ee7fb1519d9898aefc262f2565923c4fe41bbc06f57e0 tests/test_openapi.py
6e63ed05db0490148d1c8428d785a23b0d5d5a0f566cd397c9c4a8fe8a6ed7dc tests/test_option.py
cde0bea1263ae857561f91ed2bd515e972b716743f017d31b1718a8546c72759 tests/test_pagecontent.py
fc698e34b53e95c2cc190dadb087d5873711202b2c5eef9db9fc6de5f9c88063 tests/test_pagecontent.py
7297b791aed9278d9252a3ade688e67796eb5c9cc4d6b29e1d2b56d83aa20295 tests/test_parse_modules.py
0d52bf4b96eea2330553fdf7f875ed571e596d2f7a4b3648a2b53e44666f0c70 tests/test_payload_marking.py
6cfe189c49749a2e0bc551173f5d2c4eb5aad8cbb1f9584ecc60958b9a842725 tests/test_payload_marking.py
6bfc8201724078bd9d6d559916ef73c9ff97e19b0f2948f37e588a49b027795f tests/test_payloads_structure.py
d6ffa83bd56ae98e7f55307b72dd7ea4802bccea9a85bb8f062619fb0a88913e tests/test_progress.py
2d135eba3ad0fd091962d84742ebf67314fd3f89dcaaa1252b3e3d76fae7c9fd tests/test_property.py
c4c6f500bb71c3e430da343a49e8c8b8b3c919f438b6e6130597ce68dd856487 tests/test_purge.py
9a0915f34e1f80a2989238fcce940734cd886020c549711a8444e7ee62eab812 tests/test_purge.py
2dfefb4bfaee3868152835502ec43da317c4f274b1d55cd2ef21e4f7390c9bea tests/test_replication.py
427a543e17dfede42b9fbccc916fa0aecd93fb7bfb5c280de4c2bca87c5d8de5 tests/test_report.py
4723d3bdf9623a49972e1d7378168ae8efbeaa31fb11c35d83bb40cc135fa0a8 tests/test_request_basic.py
cec98d72992c0799229a780fa7f0d7f3fb01ec2d708187ce0e4a05c8612f291b tests/test_safe2bin.py
575ebc336be598858279094072cde1ac9b124109cd7397bd805decd1b0a616d4 tests/test_search_enum.py
a1c6cda1e5b483f61e6a4f8ddd0b06a15ddaa3fd2119bfb9dbd9cc970d7a751d tests/test_settings_regex.py
29d0278e3718b0fee422d3f6bb85ca02560138d48cd76f9fe1f35ac19d96071b tests/test_sgmllib.py
295581435c4dbf7fe6c291bbf0163c43ccb6ee610e6f3f2609bfeed734c91a1a tests/test_sgmllib.py
d3d991331096e16e5019de3d652e9fff92c09bd9f97c50b1c2c3ceb0ed49b17e tests/test_sqlparse.py
412a61053c2531cc0380b34dfd01d52bd118f6a6473728c069c467054c7e3c8e tests/test_ssti.py
19e1e17d7a94e42cf75a37901c3468c79807a2d423bd1988b6f4a2566b864f3b tests/test_ssti.py
8bcbf1091134dd0a62f6201f8b3645ed87b5ff2f7ba40a87231a29dac412591f tests/test_strings.py
8f1c5f0f337ecd26d35c5551060034e0aa33a62cce5385fc1227fdc485f6383e tests/test_tamper.py
b2b3a00254301e5e880e2e77351ebc47eed2c5280477915feedf780ea8cbd34f tests/test_target_parsing.py
b3e13febe9e0ff6f97334f2868655bfdbaa18755e464a6dc4c6d424f513bad02 tests/test_targeturl.py
cc67045d60472913eca574d601077e5111a95f4563c66caf361b8deaa2bed03c tests/test_targeturl.py
d7d8aaba1d22ee690c8da2c6e28cea0ab45b0d7a6915a5ae7f581c44d7121aab tests/test_techniques.py
639851dc68f62b559b200b09c308e64e453f414969940005bac75dc0ab07a6b6 tests/test_texthelpers.py
f49bcce1df533ffa1acfd02af43faf6687b21eebda9362ceb1e5871b8cb37fd4 tests/test_threads.py
61769e1d6c4429659ebfb2de696b506821e3c6f3ca81b4318ce790b9553ca6a3 tests/test_texthelpers.py
095a889a6274f0f8e437bf9a23e4b073ab6c4b60aba582e6d1e2099645f1d883 tests/test_threads.py
8d23cb42cde68e0da2c4b47db367139d0c53363fef7493ae70b7f6636a1bbbc7 tests/test_union_engine.py
48b0ae4abe0fdde8ce4975c5cbf4c3514a2815021cb2e3a490a189bea5edfe78 tests/test_unpickle_security.py
4b646f513c6da1e33200184ed6eabe0aa345eb2e2a19598dc123e191168591bf tests/test_urls.py

View file

@ -2099,7 +2099,9 @@ def getFileType(filePath):
desc = getText(desc)
if desc == getText(magic.MAGIC_UNKNOWN_FILETYPE):
content = openFile(filePath, "rb", encoding=None).read()
_ = openFile(filePath, "rb", encoding=None)
content = _.read()
_.close()
try:
content.decode()

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.20"
VERSION = "1.10.7.21"
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

@ -75,6 +75,8 @@ def configFileParser(configFile):
except Exception as ex:
errMsg = "you have provided an invalid and/or unreadable configuration file ('%s')" % getSafeExString(ex)
raise SqlmapSyntaxException(errMsg)
finally:
configFP.close()
if not config.has_section("Target"):
errMsg = "missing a mandatory section 'Target' in the configuration file"

View file

@ -1225,6 +1225,7 @@ def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc
pass
finally:
wordlist.closeFP() # release the wordlist file handle (else it leaks; Windows can't rmtree an open file)
if hasattr(proc_count, "value"):
with proc_count.get_lock():
proc_count.value -= 1
@ -1304,6 +1305,7 @@ def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found
pass
finally:
wordlist.closeFP() # release the wordlist file handle (else it leaks; Windows can't rmtree an open file)
if hasattr(proc_count, "value"):
with proc_count.get_lock():
proc_count.value -= 1

View file

@ -86,6 +86,7 @@ class _ApiServerCase(unittest.TestCase):
"""
def setUp(self):
self._saved_batch = conf.batch
conf.batch = True
# snapshot mutated globals
@ -122,6 +123,7 @@ class _ApiServerCase(unittest.TestCase):
api.DataStore.username = self._saved["username"]
api.DataStore.password = self._saved["password"]
api.Database.filepath = self._saved["filepath"]
conf.batch = self._saved_batch
def _new_task(self):
code, parsed, _ = _wsgi_call("GET", "/task/new")

View file

@ -28,14 +28,26 @@ from lib.core.bigarray import BigArray
N = 5000
_SPILLED = []
def _make_spilled():
# tiny chunk_size guarantees many on-disk chunks for N items
ba = BigArray(chunk_size=1024)
for i in range(N):
ba.append("item-%d" % i)
_SPILLED.append(ba) # tracked so tearDownModule closes it (release the on-disk chunk files)
return ba
def tearDownModule():
for ba in _SPILLED:
try:
ba.close()
except Exception:
pass
del _SPILLED[:]
class TestSpill(unittest.TestCase):
def test_actually_spilled_to_disk(self):
ba = _make_spilled()

View file

@ -53,9 +53,10 @@ _CONF_KEYS = (
"notString", "regexp", "regex", "dummy", "offline", "skipWaf", "data",
"hashDB", "cj", "cookie", "dropSetCookie", "httpHeaders", "proxy", "tor",
"tamper", "timeout", "retries", "textOnly", "ignoreCode", "disablePrecon",
"ipv6", "multipleTargets", "level", "base64Parameter", "batch",
"ipv6", "multipleTargets", "level", "base64Parameter", "batch", "code", "titles",
)
_KB_KEYS = (
"pageTemplate", "negativeLogic",
"heavilyDynamic", "dynamicParameter", "originalPage", "originalPageTime",
"originalCode", "ignoreCasted", "heuristicMode", "disableHtmlDecoding",
"heuristicTest", "heuristicPage", "heuristicCode", "pageStable",

View file

@ -1320,10 +1320,9 @@ class TestCommonChunkSplit(unittest.TestCase):
random.choice, random.randint, random.sample, random.seed = _saved
def test_chunk_split_terminator(self):
import random
from lib.core.common import chunkSplitPostData
random.seed(123)
# regardless of content, the chunked stream must end with the zero-length terminator
# (assertion is seed-independent, so don't touch the global RNG)
self.assertTrue(chunkSplitPostData("abc").endswith("0\r\n\r\n"))

View file

@ -25,6 +25,7 @@ logic fails the test. No live target / network / DBMS involved.
import os
import sys
import tempfile
import unittest
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
@ -108,7 +109,7 @@ class TestGenericFilesystem(_FsBase):
def test_fileEncode_reads_then_encodes(self):
# fileEncode must read the file bytes and delegate to fileContentEncode
path = os.path.join(
os.environ.get("TMPDIR", "/tmp"), "sqlmap_fe_%d.bin" % os.getpid())
tempfile.gettempdir(), "sqlmap_fe_%d.bin" % os.getpid())
with open(path, "wb") as f:
f.write(b"hello")
try:
@ -138,7 +139,7 @@ class TestGenericFilesystem(_FsBase):
# MySQL builds LENGTH(LOAD_FILE('<remote>')) and compares to local size.
set_dbms("MySQL")
path = os.path.join(
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl_%d.bin" % os.getpid())
tempfile.gettempdir(), "sqlmap_cl_%d.bin" % os.getpid())
with open(path, "wb") as f:
f.write(b"12345") # 5 bytes
captured = {}
@ -159,7 +160,7 @@ class TestGenericFilesystem(_FsBase):
def test_checkFileLength_size_differs(self):
set_dbms("MySQL")
path = os.path.join(
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl2_%d.bin" % os.getpid())
tempfile.gettempdir(), "sqlmap_cl2_%d.bin" % os.getpid())
with open(path, "wb") as f:
f.write(b"12345") # local 5
self.patch(self.module.inject, "getValue", lambda q, *a, **k: "9")
@ -176,7 +177,7 @@ class TestGenericFilesystem(_FsBase):
# OPENROWSET-building branch runs in isolation.
set_dbms("Microsoft SQL Server")
path = os.path.join(
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl3_%d.bin" % os.getpid())
tempfile.gettempdir(), "sqlmap_cl3_%d.bin" % os.getpid())
with open(path, "wb") as f:
f.write(b"ABCD") # 4 bytes
stacked = []
@ -205,7 +206,7 @@ class TestGenericFilesystem(_FsBase):
# non-positive remote size -> treated as "not written" -> sameFile False
set_dbms("MySQL")
path = os.path.join(
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl4_%d.bin" % os.getpid())
tempfile.gettempdir(), "sqlmap_cl4_%d.bin" % os.getpid())
with open(path, "wb") as f:
f.write(b"x")
self.patch(self.module.inject, "getValue", lambda q, *a, **k: None)
@ -282,7 +283,7 @@ class TestGenericFilesystem(_FsBase):
# stackedWriteFile and return its result.
set_dbms("MySQL")
path = os.path.join(
os.environ.get("TMPDIR", "/tmp"), "sqlmap_wf_%d.bin" % os.getpid())
tempfile.gettempdir(), "sqlmap_wf_%d.bin" % os.getpid())
with open(path, "wb") as f:
f.write(b"data")
calls = {}

View file

@ -16,6 +16,21 @@ bootstrap()
import lib.techniques.ldap.inject as ldap
# several setUps here write these conf keys without restoring them; snapshot/restore at the module
# boundary so they can't leak into later test modules (order-dependent flakiness)
_LDAP_CONF_KEYS = ("parameters", "paramDict", "skipUrlEncode", "cookieDel")
_saved_conf = {}
def setUpModule():
from lib.core.data import conf
for k in _LDAP_CONF_KEYS:
_saved_conf[k] = conf.get(k)
def tearDownModule():
from lib.core.data import conf
for k, v in _saved_conf.items():
conf[k] = v
# --- Helpers ----------------------------------------------------------------
SENTINEL = ldap.SENTINEL

View file

@ -18,6 +18,21 @@ bootstrap()
import lib.techniques.nosql.inject as ni
# several setUps here write these conf keys without restoring them; snapshot/restore at the module
# boundary so they can't leak into later test modules (order-dependent flakiness)
_NOSQL_CONF_KEYS = ("parameters", "paramDict", "timeSec", "cookieDel")
_saved_conf = {}
def setUpModule():
from lib.core.data import conf
for k in _NOSQL_CONF_KEYS:
_saved_conf[k] = conf.get(k)
def tearDownModule():
from lib.core.data import conf
for k, v in _saved_conf.items():
conf[k] = v
SECRET = "S3cr3t_9"
MATCH = "<html><body>Welcome user; rows: alpha, bravo, charlie</body></html>"
NOMATCH = "<html><body>Invalid credentials; no rows</body></html>"

View file

@ -60,6 +60,7 @@ class TestExtractTextTagContent(unittest.TestCase):
class TestParseSqliteTableSchema(unittest.TestCase):
def setUp(self):
self.addCleanup(setattr, kb.data, "cachedColumns", kb.data.get("cachedColumns"))
kb.data.cachedColumns = {}
def _cols(self):

View file

@ -28,6 +28,24 @@ from lib.core.settings import (JSON_RECOGNITION_REGEX, JSON_LIKE_RECOGNITION_REG
# change there is reflected here too.
MARK = CUSTOM_INJECTION_MARK_CHAR
# the _drive_* helpers set sticky conf/kb flags (notably conf.hpp, which changes queryPage
# behaviour) without restoring them; snapshot/restore at the module boundary so they can't leak
_PM_CONF_KEYS = ("hpp", "skipUrlEncode", "method", "paramDel", "url", "data", "parameters", "paramDict")
_PM_KB_KEYS = ("tamperFunctions", "postHint", "customInjectionMark", "postUrlEncode", "postSpaceToPlus", "processUserMarks")
_pm_saved = {}
def setUpModule():
from lib.core.data import conf, kb
for k in _PM_CONF_KEYS:
_pm_saved[("conf", k)] = conf.get(k)
for k in _PM_KB_KEYS:
_pm_saved[("kb", k)] = kb.get(k)
def tearDownModule():
from lib.core.data import conf, kb
for (scope, k), v in _pm_saved.items():
(conf if scope == "conf" else kb)[k] = v
def classify(d):
if re.search(JSON_RECOGNITION_REGEX, d):

View file

@ -83,7 +83,10 @@ class TestPurge(unittest.TestCase):
nonempty = [p for p in survivors if os.path.getsize(p) > 0]
self.assertEqual(nonempty, [], msg="files were not truncated to zero: %r" % nonempty)
blob = b"".join(open(p, "rb").read() for p in survivors)
blob = b""
for p in survivors:
with open(p, "rb") as fh:
blob += fh.read()
for secret in plaintexts.values():
self.assertNotIn(secret.encode("utf-8"), blob,
msg="original plaintext %r survived the purge" % secret)

View file

@ -191,6 +191,7 @@ class TestEntityConversion(unittest.TestCase):
class TestCustomEntitydefs(unittest.TestCase):
def test_custom_entity(self):
p = RecordingParser()
p.entitydefs = dict(p.entitydefs) # shadow the shared SGMLParser class dict so 'copy' doesn't leak process-wide
p.entitydefs["copy"] = "\xa9"
p.feed("&copy;")
p.close()

View file

@ -393,8 +393,7 @@ class TestExecuteCommand(unittest.TestCase):
def tearDown(self):
ssti._send = self.original_send
if self.original_dumper is not None:
ssti.conf.dumper = self.original_dumper
ssti.conf.dumper = self.original_dumper # restore unconditionally (was None -> don't leak the mock dumper)
def test_error_page_skipped(self):
"""RCE payload that triggers a template error is skipped; next payload tried."""

View file

@ -26,6 +26,20 @@ bootstrap()
from lib.core.common import parseTargetUrl
from lib.core.data import conf
_TARGETURL_KEYS = ("url", "hostname", "port", "scheme", "path")
_saved = {}
def setUpModule():
for k in _TARGETURL_KEYS:
_saved[k] = conf.get(k)
def tearDownModule():
# parseTargetUrl() writes these onto the global conf singleton; restore so it can't leak to later modules
for k, v in _saved.items():
conf[k] = v
def _parse(url):
conf.url = url

View file

@ -46,6 +46,7 @@ class TestFilterStringValue(unittest.TestCase):
class TestParseFilePaths(unittest.TestCase):
def setUp(self):
self.addCleanup(setattr, kb, "absFilePaths", kb.get("absFilePaths"))
kb.absFilePaths = set()
def test_unix_paths_from_php_error(self):

View file

@ -38,6 +38,7 @@ class TestThreadData(unittest.TestCase):
# ATTRIBUTE STATE is per-thread. Verify both: same object, independent state.
main = T.getCurrentThreadData()
self.assertIs(main, T.getCurrentThreadData()) # stable within a thread
self.addCleanup(main.reset) # don't leak the main thread's mutated state to later tests
main.retriesCount = 111