mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-07-01 14:01:09 +00:00
Minor refactoring
This commit is contained in:
parent
e0269acc0d
commit
f932a3f30f
6 changed files with 30 additions and 139 deletions
|
|
@ -181,7 +181,7 @@ f8de57606325456928e46ae2896f5f8bbec9ad18b1c644b492a566fa992216f6 lib/core/decor
|
|||
5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py
|
||||
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py
|
||||
914a13ee21fd610a6153a37cbe50830fcbd1324c7ebc1e7fc206d5e598b0f7ad lib/core/log.py
|
||||
33ed53b263fa766a808be6797dd812822bb115d3b9db6e3a34763f500f5359e8 lib/core/optiondict.py
|
||||
5a576f802f1298d0aa357e766ae6502fa53cacbbe0b1d328b7410a8b20a885b2 lib/core/optiondict.py
|
||||
e033b20a0f7821797a10f4bf4235723f38c7db551c611fbb713faa621b123c4a lib/core/option.py
|
||||
21b2b1745107c211fc7593923a3da7a808d40763c00091c28de5f7c129bcf3bc lib/core/patch.py
|
||||
49c0fa7e3814dfda610d665ee02b12df299b28bc0b6773815b4395514ddf8dec lib/core/profiling.py
|
||||
|
|
@ -189,7 +189,7 @@ e033b20a0f7821797a10f4bf4235723f38c7db551c611fbb713faa621b123c4a lib/core/optio
|
|||
9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py
|
||||
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
|
||||
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
|
||||
2498555483d50cf55f24dcb82b3253816a1ad6c3325b17e502d5063f2c9cbc87 lib/core/settings.py
|
||||
098e5d86a0da05d4be5f5ed5371083954be2369abce57fda4bd906d12e1f8870 lib/core/settings.py
|
||||
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
|
||||
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
|
||||
19f1e3c5e3ba703d28d510cd7a9ab8284d5fbe9df5ce7e77c86e5931571364b7 lib/core/target.py
|
||||
|
|
@ -200,7 +200,7 @@ b9aacb840310173202f79c2ba125b0243003ee6b44c92eca50424f2bdfc83c02 lib/core/unesc
|
|||
2400e465fa4d13e4c32795910878c71ff212e4361b46428d57ce43983f5e997c lib/core/wordlist.py
|
||||
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/__init__.py
|
||||
54bfd31ebded3ffa5848df1c644f196eb704116517c7a3d860b5d081e984d821 lib/parse/banner.py
|
||||
316cdcb3d8d839dab639ed7eb4935780375d49c93371edbd6224976cbb968c2e lib/parse/cmdline.py
|
||||
403ebb5b54531cf907a30ed439fc881cf3cbae68c3a4ec600c75312e5f6b9001 lib/parse/cmdline.py
|
||||
02d82e4069bd98c52755417f8b8e306d79945672656ac24f1a45e7a6eff4b158 lib/parse/configfile.py
|
||||
c5b258be7485089fac9d9cd179960e774fbd85e62836dc67cce76cc028bb6aeb lib/parse/handler.py
|
||||
5c9a9caee948843d5537745640cc7b98d70a0412cc0949f59d4ebe8b2907c06c lib/parse/headers.py
|
||||
|
|
@ -247,7 +247,7 @@ c3e5cf7e5e35ae5fd86b63a515b37e6f06e61c70d2690252f2ee8373aa16637e lib/techniques
|
|||
44401cad3e39ae9fb899ed5d0e2fdd0879561de05c3117f17f3b0db54f4e3724 lib/techniques/nosql/__init__.py
|
||||
bde75d41ac3e5747b96d2af4c33922573158cb43b48714a28490d6720dd85d89 lib/techniques/nosql/inject.py
|
||||
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/ssti/__init__.py
|
||||
8eaf90c2fa517a4577467ac0d7534a927c23931b946b27e88e63ae022f794a1c lib/techniques/ssti/inject.py
|
||||
14637b64878248e5965887b07aa68e62615dac88e2ffc6c3a581430bdd4e309e lib/techniques/ssti/inject.py
|
||||
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/techniques/union/__init__.py
|
||||
ceec65f8cb7c3254c4671351c837418c76ac5bc55ccbc40779f67231b54d7085 lib/techniques/union/test.py
|
||||
c65766f71e285fc85cdf58e7448c4c1d015af2a9dbb44fa3b665a9f13362fbcc lib/techniques/union/use.py
|
||||
|
|
@ -643,7 +643,7 @@ cec98d72992c0799229a780fa7f0d7f3fb01ec2d708187ce0e4a05c8612f291b tests/test_saf
|
|||
a1c6cda1e5b483f61e6a4f8ddd0b06a15ddaa3fd2119bfb9dbd9cc970d7a751d tests/test_settings_regex.py
|
||||
29d0278e3718b0fee422d3f6bb85ca02560138d48cd76f9fe1f35ac19d96071b tests/test_sgmllib.py
|
||||
d3d991331096e16e5019de3d652e9fff92c09bd9f97c50b1c2c3ceb0ed49b17e tests/test_sqlparse.py
|
||||
4a9409a070770cc6300ed2b0c954254273479252fa602ffd19d78917f895756c tests/test_ssti.py
|
||||
412a61053c2531cc0380b34dfd01d52bd118f6a6473728c069c467054c7e3c8e tests/test_ssti.py
|
||||
8bcbf1091134dd0a62f6201f8b3645ed87b5ff2f7ba40a87231a29dac412591f tests/test_strings.py
|
||||
8f1c5f0f337ecd26d35c5551060034e0aa33a62cce5385fc1227fdc485f6383e tests/test_tamper.py
|
||||
67472bd71c20782cc0f738e2c2e674c29d6985669e14d15b69baef7d0e33de62 tests/test_target_parsing.py
|
||||
|
|
|
|||
|
|
@ -173,8 +173,6 @@ optDict = {
|
|||
"lastChar": "integer",
|
||||
"sqlQuery": "string",
|
||||
"sqlShell": "boolean",
|
||||
"sstiQuery": "string",
|
||||
"sstiShell": "boolean",
|
||||
"sqlFile": "string",
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from lib.core.enums import OS
|
|||
from thirdparty import six
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.10.6.197"
|
||||
VERSION = "1.10.6.198"
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ def cmdLineParser(argv=None):
|
|||
help="Parse target(s) from Burp or WebScarab proxy log file")
|
||||
|
||||
target.add_argument("-m", dest="bulkFile",
|
||||
help="Scan multiple targets given in a textual file ")
|
||||
help="Scan multiple targets given in a textual file")
|
||||
|
||||
target.add_argument("-r", dest="requestFile",
|
||||
help="Load HTTP request from a file")
|
||||
|
|
@ -335,7 +335,7 @@ def cmdLineParser(argv=None):
|
|||
help="Skip testing for given parameter(s)")
|
||||
|
||||
injection.add_argument("--skip-static", dest="skipStatic", action="store_true",
|
||||
help="Skip testing parameters that not appear to be dynamic")
|
||||
help="Skip testing parameters that do not appear to be dynamic")
|
||||
|
||||
injection.add_argument("--param-exclude", dest="paramExclude",
|
||||
help="Regexp to exclude parameters from testing (e.g. \"ses\")")
|
||||
|
|
@ -442,21 +442,6 @@ def cmdLineParser(argv=None):
|
|||
techniques.add_argument("--second-req", dest="secondReq",
|
||||
help="Load second-order HTTP request from file")
|
||||
|
||||
techniques.add_argument("--graphql", dest="graphql", action="store_true",
|
||||
help="Test for GraphQL injection")
|
||||
|
||||
techniques.add_argument("--ldap", dest="ldap", action="store_true",
|
||||
help="Test for LDAP injection")
|
||||
|
||||
techniques.add_argument("--nosql", dest="nosql", action="store_true",
|
||||
help="Test for NoSQL injection")
|
||||
|
||||
techniques.add_argument("--xpath", dest="xpath", action="store_true",
|
||||
help="Test for XPath injection")
|
||||
|
||||
techniques.add_argument("--ssti", dest="ssti", action="store_true",
|
||||
help="Test for server-side template injection")
|
||||
|
||||
# Fingerprint options
|
||||
fingerprint = parser.add_argument_group("Fingerprint", "These options can be used to perform a back-end database management system version fingerprint")
|
||||
|
||||
|
|
@ -515,7 +500,7 @@ def cmdLineParser(argv=None):
|
|||
help="Dump DBMS database table entries")
|
||||
|
||||
enumeration.add_argument("--dump-all", dest="dumpAll", action="store_true",
|
||||
help="Dump all DBMS databases tables entries")
|
||||
help="Dump entries of all DBMS database tables")
|
||||
|
||||
enumeration.add_argument("--search", dest="search", action="store_true",
|
||||
help="Search column(s), table(s) and/or database name(s)")
|
||||
|
|
@ -571,12 +556,6 @@ def cmdLineParser(argv=None):
|
|||
enumeration.add_argument("--sql-shell", dest="sqlShell", action="store_true",
|
||||
help="Prompt for an interactive SQL shell")
|
||||
|
||||
enumeration.add_argument("--ssti-query", dest="sstiQuery",
|
||||
help="SSTI expression to evaluate in-band on the vulnerable parameter")
|
||||
|
||||
enumeration.add_argument("--ssti-shell", dest="sstiShell", action="store_true",
|
||||
help="Prompt for an interactive SSTI expression shell")
|
||||
|
||||
enumeration.add_argument("--sql-file", dest="sqlFile",
|
||||
help="Execute SQL statements from given file(s)")
|
||||
|
||||
|
|
@ -626,11 +605,10 @@ def cmdLineParser(argv=None):
|
|||
help="Prompt for an OOB shell, Meterpreter or VNC")
|
||||
|
||||
takeover.add_argument("--os-smbrelay", dest="osSmb", action="store_true",
|
||||
help="One click prompt for an OOB shell, Meterpreter or VNC")
|
||||
help="One-click prompt for an OOB shell, Meterpreter or VNC")
|
||||
|
||||
takeover.add_argument("--os-bof", dest="osBof", action="store_true",
|
||||
help="Stored procedure buffer overflow "
|
||||
"exploitation")
|
||||
help="Stored procedure buffer overflow exploitation")
|
||||
|
||||
takeover.add_argument("--priv-esc", dest="privEsc", action="store_true",
|
||||
help="Database process user privilege escalation")
|
||||
|
|
@ -788,6 +766,24 @@ def cmdLineParser(argv=None):
|
|||
general.add_argument("--web-root", dest="webRoot",
|
||||
help="Web server document root directory (e.g. \"/var/www\")")
|
||||
|
||||
# Non-SQL injection options
|
||||
nonsql = parser.add_argument_group("Non-SQL injection", "These options can be used to test for non-SQL injection types")
|
||||
|
||||
nonsql.add_argument("--graphql", dest="graphql", action="store_true",
|
||||
help="Test for GraphQL injection")
|
||||
|
||||
nonsql.add_argument("--ldap", dest="ldap", action="store_true",
|
||||
help="Test for LDAP injection")
|
||||
|
||||
nonsql.add_argument("--nosql", dest="nosql", action="store_true",
|
||||
help="Test for NoSQL injection")
|
||||
|
||||
nonsql.add_argument("--xpath", dest="xpath", action="store_true",
|
||||
help="Test for XPath injection")
|
||||
|
||||
nonsql.add_argument("--ssti", dest="ssti", action="store_true",
|
||||
help="Test for server-side template injection")
|
||||
|
||||
# Miscellaneous options
|
||||
miscellaneous = parser.add_argument_group("Miscellaneous", "These options do not fit into any other category")
|
||||
|
||||
|
|
|
|||
|
|
@ -59,12 +59,6 @@ def _arithmeticPayload(fmt, a, b):
|
|||
return fmt.replace("%d", str(a), 1).replace("%d", str(b), 1)
|
||||
|
||||
|
||||
def _expressionPayload(fmt, value):
|
||||
# Same rationale as _arithmeticPayload(): literal %s substitution so '%'-delimited engines
|
||||
# (notably ERB) can wrap expressions instead of crashing on fmt % value.
|
||||
return fmt.replace("%s", value, 1)
|
||||
|
||||
|
||||
def _degroup(text):
|
||||
# Strip digit-group (thousands) separators so an arithmetic result still matches when the
|
||||
# engine formats large numbers with grouping (e.g. FreeMarker renders 234*567 as "132,678").
|
||||
|
|
@ -642,7 +636,7 @@ def sstiScan():
|
|||
place, parameter, engine, evidence = slot
|
||||
from lib.core.common import readInput
|
||||
|
||||
wantsTakeover = any(conf.get(_) for _ in ("osCmd", "osShell", "sstiQuery", "sstiShell"))
|
||||
wantsTakeover = any(conf.get(_) for _ in ("osCmd", "osShell"))
|
||||
|
||||
# If the user did not ask for exploitation, confirm (benignly) whether OS command
|
||||
# execution is reachable and, if so, advise the relevant switches.
|
||||
|
|
@ -651,20 +645,6 @@ def sstiScan():
|
|||
"you are advised to try '--os-shell' (interactive) or "
|
||||
"'--os-cmd=<command>' (single command)" % engine.name)
|
||||
|
||||
# --ssti-query: user-provided expression evaluated in-band
|
||||
if conf.get("sstiQuery"):
|
||||
_evalExpression(place, parameter, engine, conf.sstiQuery)
|
||||
|
||||
# --ssti-shell: interactive expression evaluation loop (interactive even under --batch,
|
||||
# like sqlmap's SQL --sql-shell/--os-shell, which read straight from the terminal)
|
||||
if conf.get("sstiShell"):
|
||||
logger.info("calling SSTI shell. Enter expressions (e.g. 7*7) or 'exit'/'quit' to leave")
|
||||
while True:
|
||||
expr = readInput("ssti-shell> ", checkBatch=False)
|
||||
if not expr or expr.strip().lower() in ("exit", "quit"):
|
||||
break
|
||||
_evalExpression(place, parameter, engine, expr.strip())
|
||||
|
||||
# --os-cmd / --os-shell: RCE via SSTI (reuses existing SQL takeover flags)
|
||||
if conf.get("osCmd") or conf.get("osShell"):
|
||||
if not _canTakeover(engine, evidence):
|
||||
|
|
@ -692,56 +672,6 @@ def _escapeSingleQuoted(value):
|
|||
return value.replace("\\", "\\\\").replace("'", "\\'")
|
||||
|
||||
|
||||
def _evalExpression(place, parameter, engine, expr):
|
||||
"""Wrap expr in the engine's expression format, extract result between
|
||||
random markers for deterministic output, fall back to baseline diff."""
|
||||
|
||||
if not engine.expressionFmt:
|
||||
logger.error("expression evaluation not supported for engine '%s'" % engine.name)
|
||||
return
|
||||
|
||||
original = _originalValue(place, parameter) or ""
|
||||
startMarker = randomStr(length=8, lowercase=True)
|
||||
endMarker = randomStr(length=8, lowercase=True)
|
||||
|
||||
# Three-part payload: marker, expression, marker -- each in its own template tag
|
||||
# so the expression is evaluated independently of the markers
|
||||
payload = original + _expressionPayload(engine.expressionFmt, "'%s'" % startMarker)
|
||||
payload += " " + _expressionPayload(engine.expressionFmt, expr)
|
||||
payload += " " + _expressionPayload(engine.expressionFmt, "'%s'" % endMarker)
|
||||
page = _send(place, parameter, payload)
|
||||
|
||||
if not page:
|
||||
logger.warning("no response for SSTI expression '%s'" % expr)
|
||||
return
|
||||
|
||||
text = getUnicode(page)
|
||||
result = None
|
||||
|
||||
# Extract content between the random markers
|
||||
if startMarker in text and endMarker in text:
|
||||
start = text.index(startMarker) + len(startMarker)
|
||||
end = text.index(endMarker, start)
|
||||
result = text[start:end].strip()
|
||||
|
||||
# Fallback: diff against baseline
|
||||
if not result:
|
||||
baseline = _send(place, parameter, original)
|
||||
if baseline:
|
||||
sm = difflib.SequenceMatcher(None, getUnicode(baseline), text)
|
||||
parts = []
|
||||
for tag, i1, i2, j1, j2 in sm.get_opcodes():
|
||||
if tag in ("insert", "replace"):
|
||||
parts.append(text[j1:j2])
|
||||
if parts:
|
||||
result = "".join(parts).strip()
|
||||
|
||||
if result:
|
||||
conf.dumper.singleString("SSTI expression result: %s" % result)
|
||||
else:
|
||||
logger.warning("could not extract expression result from response")
|
||||
|
||||
|
||||
def _canTakeover(engine, evidence):
|
||||
"""Require exact engine fingerprint (not a family guess) and confirmed
|
||||
proof before attempting OS command execution."""
|
||||
|
|
|
|||
|
|
@ -275,39 +275,6 @@ class TestCrossEngineDisambiguation(unittest.TestCase):
|
|||
self.assertIn("Twig", engine.name)
|
||||
|
||||
|
||||
class TestExpressionEvaluation(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.original_send = ssti._send
|
||||
|
||||
def tearDown(self):
|
||||
ssti._send = self.original_send
|
||||
|
||||
def test_eval_uses_expressionFmt(self):
|
||||
engine = ssti._ENGINE_TABLE[0] # Jinja2: expressionFmt = "{{ %s }}"
|
||||
results = []
|
||||
|
||||
def mock(place, parameter, value):
|
||||
results.append(value)
|
||||
return "Hello __marker__ 49 __marker2__"
|
||||
|
||||
ssti._send = mock
|
||||
ssti._evalExpression("GET", "q", engine, "7*7")
|
||||
# Payload must use expressionFmt, not raw delimiter concatenation
|
||||
self.assertIn("{{ ", results[0])
|
||||
self.assertIn(" }}", results[0])
|
||||
|
||||
def test_eval_falls_back_when_no_expressionFmt(self):
|
||||
engine = [e for e in ssti._ENGINE_TABLE if e.name == "Handlebars"][0]
|
||||
self.assertEqual(engine.expressionFmt, "")
|
||||
|
||||
def mock(place, parameter, value):
|
||||
return "irrelevant"
|
||||
|
||||
ssti._send = mock
|
||||
# Should not raise; just logs error
|
||||
ssti._evalExpression("GET", "q", engine, "7*7")
|
||||
|
||||
|
||||
class TestBooleanUniqueness(unittest.TestCase):
|
||||
def test_jinja2_boolean_unique_among_curlies(self):
|
||||
jinja2 = ssti._ENGINE_TABLE[0]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue