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 ASP_NET_CONTROL_REGEX
|
||||||
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
|
from lib.core.settings import CSRF_TOKEN_PARAMETER_INFIXES
|
||||||
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
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 EMPTY_FORM_FIELDS_REGEX
|
||||||
from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_REGEX
|
from lib.core.settings import GOOGLE_ANALYTICS_COOKIE_REGEX
|
||||||
from lib.core.settings import HASHDB_STALE_DAYS
|
from lib.core.settings import HASHDB_STALE_DAYS
|
||||||
@@ -532,12 +533,12 @@ def start():
|
|||||||
|
|
||||||
checkJWT()
|
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
|
from lib.utils.paraminer import mineParameters
|
||||||
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):
|
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 (--graphql/--nosql/--ldap/--xpath/--ssti/--xslt/--xxe/--hql/--sparql/--odata/--jwt) findings; these are reported on the console only")
|
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:
|
if conf.graphql:
|
||||||
from lib.techniques.graphql.inject import graphqlScan
|
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 PRECONNECT_CANDIDATE_TIMEOUT
|
||||||
from lib.core.settings import PROXY_ENVIRONMENT_VARIABLES
|
from lib.core.settings import PROXY_ENVIRONMENT_VARIABLES
|
||||||
from lib.core.settings import SOCKET_PRE_CONNECT_QUEUE_SIZE
|
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 SQLMAP_ENVIRONMENT_PREFIX
|
||||||
from lib.core.settings import SUPPORTED_DBMS
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
from lib.core.settings import SUPPORTED_OS
|
from lib.core.settings import SUPPORTED_OS
|
||||||
@@ -2763,9 +2764,7 @@ def _checkTor():
|
|||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
def _basicOptionValidation():
|
def _basicOptionValidation():
|
||||||
_nonSqlTechniques = [name for name, enabled in (
|
_nonSqlTechniques = ["--%s" % _ for _ in NONSQL_TECHNIQUES if conf.get(_)]
|
||||||
("--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]
|
|
||||||
if len(_nonSqlTechniques) > 1:
|
if len(_nonSqlTechniques) > 1:
|
||||||
errMsg = "only one non-SQL technique switch may be used at a time (found: %s). " % ", ".join(_nonSqlTechniques)
|
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"
|
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
|
from thirdparty import six
|
||||||
|
|
||||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
# 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 = "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)
|
||||||
@@ -1416,6 +1416,13 @@ HQL_ERROR_SIGNATURES = (
|
|||||||
|
|
||||||
HQL_ERROR_REGEX = r"(?i)(?:%s)" % '|'.join(regex for _, regex in 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
|
# 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
|
# '--jwt' audit streams the shipped wordlist instead); these are the secrets seen over and over in
|
||||||
# tutorials, framework defaults and CTFs
|
# tutorials, framework defaults and CTFs
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ shared state stays pristine for the other test files in the suite.
|
|||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -28,13 +29,17 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|||||||
from _testutils import bootstrap
|
from _testutils import bootstrap
|
||||||
bootstrap()
|
bootstrap()
|
||||||
|
|
||||||
|
_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
from lib.core.data import conf, kb, logger
|
from lib.core.data import conf, kb, logger
|
||||||
from lib.core.common import Backend
|
from lib.core.common import Backend
|
||||||
from lib.core.enums import AUTH_TYPE
|
from lib.core.enums import AUTH_TYPE
|
||||||
|
from lib.core.optiondict import optDict
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.settings import DEFAULT_USER_AGENT
|
from lib.core.settings import DEFAULT_USER_AGENT
|
||||||
from lib.core.settings import IGNORE_CODE_WILDCARD
|
from lib.core.settings import IGNORE_CODE_WILDCARD
|
||||||
from lib.core.settings import MAX_CONNECT_RETRIES
|
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 SqlmapFilePathException
|
||||||
from lib.core.exception import SqlmapGenericException
|
from lib.core.exception import SqlmapGenericException
|
||||||
from lib.core.exception import SqlmapMissingMandatoryOptionException
|
from lib.core.exception import SqlmapMissingMandatoryOptionException
|
||||||
@@ -713,6 +718,37 @@ class TestBasicOptionValidation(_BackendGuard):
|
|||||||
self._base()
|
self._base()
|
||||||
option._basicOptionValidation() # must not raise
|
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):
|
def test_bad_level_raises(self):
|
||||||
with _preserve(conf, *self._KEYS):
|
with _preserve(conf, *self._KEYS):
|
||||||
self._base()
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main(verbosity=2)
|
unittest.main(verbosity=2)
|
||||||
|
|||||||
Reference in New Issue
Block a user