Adding gadget fallback for non-query statement execution without stacked queries (PostgreSQL dblink)

This commit is contained in:
Miroslav Štampar
2026-08-18 11:35:54 +02:00
parent 8a3b312950
commit 529fc7aebb
7 changed files with 58 additions and 3 deletions
+1
View File
@@ -2255,6 +2255,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.forkNote = None
kb.futileUnion = None
kb.fuzzUnionTest = None
kb.gadget = None
kb.heavilyDynamic = False
kb.headersFile = None
kb.headersFp = {}
+1 -1
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.8.47"
VERSION = "1.10.8.48"
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)
+45
View File
@@ -48,6 +48,9 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.convert import encodeHex
from lib.core.convert import getBytes
from lib.core.convert import getUnicode
from lib.core.decorators import lockedmethod
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
@@ -834,6 +837,36 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
return extractExpectedValue(value, expected)
def getGadget():
"""
Returns a 'gadget' (a side-effecting scalar expression usable through a
regular - e.g. boolean/time-based - injection) that can run an arbitrary
statement when stacked queries are not available (e.g. dblink_exec() on
PostgreSQL). Detection is done once and cached inside 'kb.gadget'.
"""
if kb.gadget is None:
kb.gadget = False
dbms = Backend.getIdentifiedDbms()
if dbms is not None and "gadgets" in queries[dbms]:
for name, gadget in queries[dbms].gadgets.__dict__.items():
try:
available = checkBooleanExpression(gadget.check)
except Exception:
available = False
if available:
infoMsg = "using '%s' gadget to run statement(s) as " % name
infoMsg += "stacked queries are not available"
logger.info(infoMsg)
kb.gadget = gadget
break
return kb.gadget or None
def goStacked(expression, silent=False):
if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data:
setTechnique(PAYLOAD.TECHNIQUE.STACKED)
@@ -849,6 +882,18 @@ def goStacked(expression, silent=False):
if conf.direct:
return direct(expression)
if PAYLOAD.TECHNIQUE.STACKED not in kb.injection.data:
gadget = getGadget()
if gadget:
warnMsg = "statement execution through a gadget is best-effort "
warnMsg += "and its result (if any) can not be retrieved"
singleTimeWarnMessage(warnMsg)
payload = getUnicode(gadget.command) % getUnicode(encodeHex(getBytes(expression), binary=False))
checkBooleanExpression("(%s) IS NOT NULL" % payload)
return
query = agent.prefixQuery(";%s" % expression)
query = agent.suffixQuery(query)
payload = agent.payload(newValue=query)