Minor refactoring

This commit is contained in:
Miroslav Štampar 2026-06-30 20:45:46 +02:00
parent e0269acc0d
commit f932a3f30f
6 changed files with 30 additions and 139 deletions

View file

@ -173,8 +173,6 @@ optDict = {
"lastChar": "integer",
"sqlQuery": "string",
"sqlShell": "boolean",
"sstiQuery": "string",
"sstiShell": "boolean",
"sqlFile": "string",
},

View file

@ -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)

View file

@ -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")

View file

@ -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."""