sqlmap/tests/test_payloads_structure.py
2026-06-15 09:50:47 +02:00

110 lines
4.2 KiB
Python

#!/usr/bin/env python
"""
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
Structural invariants of the injection payload/boundary definitions
(data/xml/payloads/*.xml -> conf.tests, data/xml/boundaries.xml -> conf.boundaries).
These XML files ARE the detection engine: every test/boundary loaded here is
something sqlmap will fire at a target. The fields are pure data, so the right
tests are shape/range invariants - a malformed level, an unknown technique, a
duplicate title, or a test missing its request payload would silently break or
skew detection.
"""
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from _testutils import bootstrap
bootstrap()
from lib.parse.payloads import loadBoundaries, loadPayloads
from lib.core.data import conf
from lib.core.enums import PAYLOAD
from lib.core.common import getPublicTypeMembers
# load once for the module
loadBoundaries()
loadPayloads()
TECHNIQUES = set(v for _, v in getPublicTypeMembers(PAYLOAD.TECHNIQUE)) # {1..6}
WHERES = set(v for _, v in getPublicTypeMembers(PAYLOAD.WHERE)) # {1,2,3}
class TestLoaded(unittest.TestCase):
# floors well below the current counts (~340 tests, ~54 boundaries) - high enough to catch a
# truncated/partially-loaded XML set (not just "> 0"), low enough to survive normal additions
def test_payloads_loaded(self):
self.assertGreaterEqual(len(conf.tests), 200, msg="only %d tests loaded" % len(conf.tests))
def test_boundaries_loaded(self):
self.assertGreaterEqual(len(conf.boundaries), 30, msg="only %d boundaries loaded" % len(conf.boundaries))
class TestTestEntries(unittest.TestCase):
def setUp(self):
# guard against vacuous passes: if payloads failed to load, every loop below
# would iterate zero times and pass silently
self.assertTrue(conf.tests, "conf.tests is empty - payloads failed to load")
def test_required_fields_present(self):
for t in conf.tests:
for field in ("title", "stype", "clause", "where", "level", "risk", "request", "response"):
self.assertIn(field, t, msg="test %r missing field %r" % (t.get("title"), field))
def test_title_non_empty(self):
for t in conf.tests:
self.assertTrue(t.title and t.title.strip(), msg="empty test title")
def test_titles_unique(self):
titles = [t.title for t in conf.tests]
self.assertEqual(len(titles), len(set(titles)), msg="duplicate test titles exist")
def test_stype_is_known_technique(self):
for t in conf.tests:
self.assertIn(t.stype, TECHNIQUES, msg="test %r has unknown stype %r" % (t.title, t.stype))
def test_level_and_risk_in_range(self):
for t in conf.tests:
self.assertIn(t.level, (1, 2, 3, 4, 5), msg="test %r bad level %r" % (t.title, t.level))
self.assertIn(t.risk, (1, 2, 3), msg="test %r bad risk %r" % (t.title, t.risk))
def test_request_has_payload(self):
for t in conf.tests:
self.assertIn("payload", t.request, msg="test %r request has no payload" % t.title)
def test_where_values_valid(self):
for t in conf.tests:
for w in t.where:
self.assertIn(w, WHERES, msg="test %r has bad where %r" % (t.title, w))
class TestBoundaryEntries(unittest.TestCase):
def setUp(self):
self.assertTrue(conf.boundaries, "conf.boundaries is empty - boundaries failed to load")
def test_required_fields_present(self):
for b in conf.boundaries:
for field in ("level", "clause", "where", "ptype"):
self.assertIn(field, b, msg="boundary missing field %r" % field)
def test_level_in_range(self):
for b in conf.boundaries:
self.assertIn(b.level, (1, 2, 3, 4, 5), msg="boundary bad level %r" % b.level)
def test_where_values_valid(self):
for b in conf.boundaries:
for w in b.where:
self.assertIn(w, WHERES, msg="boundary bad where %r" % w)
def test_clause_is_list_like(self):
for b in conf.boundaries:
self.assertTrue(isinstance(b.clause, (list, tuple)), msg="boundary clause not list-like")
if __name__ == "__main__":
unittest.main(verbosity=2)