mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-10-12 02:22:55 +00:00
Minor patch
This commit is contained in:
@@ -70,6 +70,7 @@ from lib.core.exception import SqlmapValueException
|
||||
from lib.core.settings import ASP_NET_CONTROL_REGEX
|
||||
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
|
||||
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
||||
from lib.core.settings import NONSQL_TECHNIQUES
|
||||
from lib.core.settings import EMPTY_FORM_FIELDS_REGEX
|
||||
from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_REGEX
|
||||
from lib.core.settings import HASHDB_STALE_DAYS
|
||||
@@ -532,12 +533,12 @@ def start():
|
||||
|
||||
checkJWT()
|
||||
|
||||
if conf.mineParams and not any((conf.graphql, conf.nosql, conf.ldap, conf.xpath, conf.ssti, conf.xxe, conf.xslt, conf.hql, conf.sparql, conf.odata, conf.jwt)):
|
||||
if conf.mineParams and not any(conf.get(_) for _ in NONSQL_TECHNIQUES):
|
||||
from lib.utils.paraminer import mineParameters
|
||||
mineParameters()
|
||||
|
||||
if any((conf.graphql, conf.nosql, conf.ldap, conf.xpath, conf.ssti, conf.xxe, conf.xslt, conf.hql, conf.sparql, conf.odata, conf.jwt)) and (conf.reportJson or conf.resultsFile):
|
||||
singleTimeWarnMessage("'--report-json'/'--results-file' do not (yet) capture non-SQL technique (--graphql/--nosql/--ldap/--xpath/--ssti/--xslt/--xxe/--hql/--sparql/--odata/--jwt) findings; these are reported on the console only")
|
||||
if any(conf.get(_) for _ in NONSQL_TECHNIQUES) and (conf.reportJson or conf.resultsFile):
|
||||
singleTimeWarnMessage("'--report-json'/'--results-file' do not (yet) capture non-SQL technique (%s) findings; these are reported on the console only" % '/'.join("--%s" % _ for _ in NONSQL_TECHNIQUES))
|
||||
|
||||
if conf.graphql:
|
||||
from lib.techniques.graphql.inject import graphqlScan
|
||||
|
||||
+2
-3
@@ -128,6 +128,7 @@ from lib.core.settings import PARAMETER_SPLITTING_REGEX
|
||||
from lib.core.settings import PRECONNECT_CANDIDATE_TIMEOUT
|
||||
from lib.core.settings import PROXY_ENVIRONMENT_VARIABLES
|
||||
from lib.core.settings import SOCKET_PRE_CONNECT_QUEUE_SIZE
|
||||
from lib.core.settings import NONSQL_TECHNIQUES
|
||||
from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX
|
||||
from lib.core.settings import SUPPORTED_DBMS
|
||||
from lib.core.settings import SUPPORTED_OS
|
||||
@@ -2763,9 +2764,7 @@ def _checkTor():
|
||||
logger.info(infoMsg)
|
||||
|
||||
def _basicOptionValidation():
|
||||
_nonSqlTechniques = [name for name, enabled in (
|
||||
("--graphql", conf.graphql), ("--nosql", conf.nosql), ("--ldap", conf.ldap),
|
||||
("--xpath", conf.xpath), ("--ssti", conf.ssti), ("--xxe", conf.xxe), ("--xslt", conf.xslt), ("--hql", conf.hql), ("--sparql", conf.sparql), ("--odata", conf.odata)) if enabled]
|
||||
_nonSqlTechniques = ["--%s" % _ for _ in NONSQL_TECHNIQUES if conf.get(_)]
|
||||
if len(_nonSqlTechniques) > 1:
|
||||
errMsg = "only one non-SQL technique switch may be used at a time (found: %s). " % ", ".join(_nonSqlTechniques)
|
||||
errMsg += "each is a self-contained scan for a different back-end class - pick one"
|
||||
|
||||
@@ -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.26"
|
||||
VERSION = "1.10.8.27"
|
||||
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)
|
||||
@@ -1416,6 +1416,13 @@ HQL_ERROR_SIGNATURES = (
|
||||
|
||||
HQL_ERROR_REGEX = r"(?i)(?:%s)" % '|'.join(regex for _, regex in HQL_ERROR_SIGNATURES)
|
||||
|
||||
# The self-contained non-SQL technique switches, by conf option name (each is also its switch spelling,
|
||||
# '--<name>'). Each is a whole scan for a different back-end class, so at most one may run: the target
|
||||
# loop branches on them and the option validation rejects a pair. Kept in ONE place because it used to
|
||||
# be spelled out at every site and had already drifted - '--jwt' was missing from the validation, which
|
||||
# let '--jwt --nosql' through to run neither (conf.jwt also suppresses the passive JWT heuristic)
|
||||
NONSQL_TECHNIQUES = ("graphql", "nosql", "ldap", "xpath", "ssti", "xxe", "xslt", "hql", "sparql", "odata", "jwt")
|
||||
|
||||
# Small, fast dictionary the always-on JWT heuristic tries against an HS* signature (the full
|
||||
# '--jwt' audit streams the shipped wordlist instead); these are the secrets seen over and over in
|
||||
# tutorials, framework defaults and CTFs
|
||||
|
||||
@@ -19,6 +19,7 @@ shared state stays pristine for the other test files in the suite.
|
||||
import contextlib
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -28,13 +29,17 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _testutils import bootstrap
|
||||
bootstrap()
|
||||
|
||||
_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from lib.core.data import conf, kb, logger
|
||||
from lib.core.common import Backend
|
||||
from lib.core.enums import AUTH_TYPE
|
||||
from lib.core.optiondict import optDict
|
||||
from lib.core.enums import HTTP_HEADER
|
||||
from lib.core.settings import DEFAULT_USER_AGENT
|
||||
from lib.core.settings import IGNORE_CODE_WILDCARD
|
||||
from lib.core.settings import MAX_CONNECT_RETRIES
|
||||
from lib.core.settings import NONSQL_TECHNIQUES
|
||||
from lib.core.exception import SqlmapFilePathException
|
||||
from lib.core.exception import SqlmapGenericException
|
||||
from lib.core.exception import SqlmapMissingMandatoryOptionException
|
||||
@@ -713,6 +718,37 @@ class TestBasicOptionValidation(_BackendGuard):
|
||||
self._base()
|
||||
option._basicOptionValidation() # must not raise
|
||||
|
||||
def test_one_non_sql_technique_at_a_time(self):
|
||||
"""Every pair must be refused, and refused BY NAME - assertRaises alone would be satisfied by
|
||||
any unrelated validation error, which is how a missing entry hid here in the first place."""
|
||||
|
||||
with _preserve(conf, *(self._KEYS + NONSQL_TECHNIQUES)):
|
||||
for name in NONSQL_TECHNIQUES:
|
||||
for other in NONSQL_TECHNIQUES:
|
||||
if other == name:
|
||||
continue
|
||||
self._base()
|
||||
for _ in NONSQL_TECHNIQUES:
|
||||
conf[_] = False
|
||||
conf[name] = conf[other] = True
|
||||
try:
|
||||
option._basicOptionValidation()
|
||||
except SqlmapSyntaxException as ex:
|
||||
message = str(ex)
|
||||
self.assertIn("--%s" % name, message)
|
||||
self.assertIn("--%s" % other, message)
|
||||
else:
|
||||
self.fail("'--%s --%s' was accepted" % (name, other))
|
||||
|
||||
def test_single_non_sql_technique_passes(self):
|
||||
with _preserve(conf, *(self._KEYS + NONSQL_TECHNIQUES)):
|
||||
for name in NONSQL_TECHNIQUES:
|
||||
self._base()
|
||||
for _ in NONSQL_TECHNIQUES:
|
||||
conf[_] = False
|
||||
conf[name] = True
|
||||
option._basicOptionValidation() # must not raise
|
||||
|
||||
def test_bad_level_raises(self):
|
||||
with _preserve(conf, *self._KEYS):
|
||||
self._base()
|
||||
@@ -1586,5 +1622,31 @@ class TestOptionSetAuthCred(unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestNonSqlTechniqueRegistry(unittest.TestCase):
|
||||
"""NONSQL_TECHNIQUES governs three things that used to be spelled out separately: the target loop's
|
||||
branches, the '--mine-params'/'--report-json' gates, and the one-at-a-time validation. They had
|
||||
already drifted - '--jwt' was in the branches but not the validation, so '--jwt --nosql' was
|
||||
accepted and then ran NEITHER (the nosql branch wins, and conf.jwt suppresses the passive JWT
|
||||
heuristic). Anchoring the list to the branches that consume it is what makes the next engine safe."""
|
||||
|
||||
def _read(self, *parts):
|
||||
with open(os.path.join(_ROOT, *parts)) as f:
|
||||
return f.read()
|
||||
|
||||
def test_every_branch_is_registered(self):
|
||||
branches = set(re.findall(r"from lib\.techniques\.(\w+)\.inject import", self._read("lib", "controller", "controller.py")))
|
||||
self.assertTrue(branches)
|
||||
self.assertEqual(sorted(branches - set(NONSQL_TECHNIQUES)), [])
|
||||
|
||||
def test_every_registered_technique_has_a_branch_and_a_switch(self):
|
||||
controller = self._read("lib", "controller", "controller.py")
|
||||
cmdline = self._read("lib", "parse", "cmdline.py")
|
||||
|
||||
for name in NONSQL_TECHNIQUES:
|
||||
self.assertIn("from lib.techniques.%s.inject import" % name, controller, name)
|
||||
self.assertIn('dest="%s"' % name, cmdline, name)
|
||||
self.assertEqual(optDict["Techniques"].get(name), "boolean", name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
|
||||
Reference in New Issue
Block a user