mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-06-20 14:40:36 +00:00
132 lines
4.2 KiB
Python
132 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
|
|
|
|
The true/false/None response oracle (lib/request/comparison.py).
|
|
|
|
The seqMatcher ratio path needs a live page template and is intentionally left
|
|
to --vuln. What IS pure and worth pinning here is the short-circuit decision
|
|
table: --string / --not-string / --regexp / --code matching, and the _adjust()
|
|
negative-logic flip. These are the rules that decide whether a payload counts
|
|
as True, and they are easy to break with a refactor.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import unittest
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
from _testutils import bootstrap
|
|
bootstrap()
|
|
|
|
from lib.request.comparison import comparison, _adjust
|
|
from lib.core.common import removeReflectiveValues
|
|
from lib.core.settings import REFLECTED_VALUE_MARKER
|
|
from lib.core.data import conf, kb
|
|
|
|
|
|
def _reset_match_conf():
|
|
conf.string = conf.notString = conf.regexp = conf.code = None
|
|
|
|
|
|
class TestStringMatch(unittest.TestCase):
|
|
def setUp(self):
|
|
_reset_match_conf()
|
|
kb.negativeLogic = False
|
|
|
|
def tearDown(self):
|
|
_reset_match_conf()
|
|
|
|
def test_string_present_is_true(self):
|
|
conf.string = "WELCOME"
|
|
self.assertTrue(comparison("xx WELCOME yy", None, code=200))
|
|
|
|
def test_string_absent_is_false(self):
|
|
conf.string = "WELCOME"
|
|
self.assertFalse(comparison("nothing here", None, code=200))
|
|
|
|
|
|
class TestRegexpMatch(unittest.TestCase):
|
|
def setUp(self):
|
|
_reset_match_conf()
|
|
kb.negativeLogic = False
|
|
|
|
def tearDown(self):
|
|
_reset_match_conf()
|
|
|
|
def test_regexp_match_is_true(self):
|
|
conf.regexp = "id=\\d+"
|
|
self.assertTrue(comparison("user id=42 ok", None, code=200))
|
|
|
|
def test_regexp_nomatch_is_false(self):
|
|
conf.regexp = "id=\\d+"
|
|
self.assertFalse(comparison("user name", None, code=200))
|
|
|
|
|
|
class TestCodeMatch(unittest.TestCase):
|
|
def setUp(self):
|
|
_reset_match_conf()
|
|
kb.negativeLogic = False
|
|
|
|
def tearDown(self):
|
|
_reset_match_conf()
|
|
|
|
def test_code_match_is_true(self):
|
|
conf.code = 200
|
|
self.assertTrue(comparison("body", None, code=200))
|
|
|
|
def test_code_mismatch_is_false(self):
|
|
conf.code = 200
|
|
self.assertFalse(comparison("body", None, code=404))
|
|
|
|
|
|
class TestAdjustNegativeLogic(unittest.TestCase):
|
|
"""_adjust flips the condition under negative logic (the raw-page scheme),
|
|
but leaves None untouched and never flips when getRatioValue is requested."""
|
|
|
|
def setUp(self):
|
|
_reset_match_conf() # negative logic only applies with no string/regexp/code set
|
|
|
|
def tearDown(self):
|
|
_reset_match_conf()
|
|
kb.negativeLogic = False
|
|
|
|
def test_plain_passthrough(self):
|
|
kb.negativeLogic = False
|
|
self.assertEqual(_adjust(True, False), True)
|
|
self.assertEqual(_adjust(False, False), False)
|
|
|
|
def test_negative_logic_flips(self):
|
|
kb.negativeLogic = True
|
|
self.assertEqual(_adjust(True, False), False)
|
|
self.assertEqual(_adjust(False, False), True)
|
|
|
|
def test_negative_logic_leaves_none(self):
|
|
kb.negativeLogic = True
|
|
self.assertIsNone(_adjust(None, False))
|
|
|
|
|
|
class TestRemoveReflectiveValues(unittest.TestCase):
|
|
"""Reflected payloads are masked before comparison so a page echoing the
|
|
injected string isn't mistaken for a True/different response. Note: the
|
|
masking engages for *bordered* payloads (containing non-alpha chars), which
|
|
is what real injection payloads look like."""
|
|
|
|
def test_reflected_payload_is_masked(self):
|
|
out = removeReflectiveValues(u"id=1 UNION SELECT 1,2,3 end", u"1 UNION SELECT 1,2,3")
|
|
self.assertIn(REFLECTED_VALUE_MARKER, out)
|
|
self.assertNotIn(u"UNION SELECT 1,2,3", out)
|
|
|
|
def test_not_reflected_unchanged(self):
|
|
content = u"<html>nothing reflected here</html>"
|
|
self.assertEqual(removeReflectiveValues(content, u"1 AND 1=1"), content)
|
|
|
|
def test_none_payload_unchanged(self):
|
|
content = u"id=1 AND 1=1 end"
|
|
self.assertEqual(removeReflectiveValues(content, None), content)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|