diff --git a/data/xml/errors.xml b/data/xml/errors.xml
index c865bea5f..095c2416d 100644
--- a/data/xml/errors.xml
+++ b/data/xml/errors.xml
@@ -127,6 +127,7 @@
+
diff --git a/data/xml/queries.xml b/data/xml/queries.xml
index e2e850640..3ebac553c 100644
--- a/data/xml/queries.xml
+++ b/data/xml/queries.xml
@@ -490,12 +490,12 @@
-
+
-
-
+
+
diff --git a/lib/core/agent.py b/lib/core/agent.py
index 65ff4a421..51f79017e 100644
--- a/lib/core/agent.py
+++ b/lib/core/agent.py
@@ -720,21 +720,43 @@ class Agent(object):
warnMsg = "applying generic concatenation (CONCAT)"
singleTimeWarnMessage(warnMsg)
+ if FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms()):
+ _ = re.sub(r"(?i)%s\Z" % re.escape(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]), "", concatenatedQuery)
+ if _ != concatenatedQuery:
+ concatenatedQuery = _
+ fieldsSelectFrom = None
+
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
concatenatedQuery += "),'%s')" % kb.chars.stop
elif fieldsSelectCase:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
concatenatedQuery += "),'%s')" % kb.chars.stop
- elif fieldsSelectFrom:
+ elif fieldsSelectFrom or fieldsSelect:
+ fromTable = ""
+
_ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM "))
- concatenatedQuery = "%s),'%s')%s" % (concatenatedQuery[:_].replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1), kb.chars.stop, concatenatedQuery[_:])
+ if _:
+ concatenatedQuery, fromTable = concatenatedQuery[:_], concatenatedQuery[_:]
+
+ concatenatedQuery = re.sub(r"(?i)\ASELECT ", "", concatenatedQuery)
+ replacement = "'%s',%s,'%s'" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
+ chars = [_ for _ in replacement]
+
+ count = 0
+ for index in zeroDepthSearch(replacement, ',')[1:]:
+ chars[index] = "),"
+ count += 1
+
+ replacement = "CONCAT(%s%s)" % ("CONCAT(" * count, "".join(chars))
+ concatenatedQuery = "%s%s" % (replacement, fromTable)
elif fieldsSelect:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1)
concatenatedQuery += "),'%s')" % kb.chars.stop
elif fieldsNoSelect:
concatenatedQuery = "CONCAT(CONCAT('%s',%s),'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
+
return concatenatedQuery
def forgeUnionQuery(self, query, position, count, comment, prefix, suffix, char, where, multipleUnions=None, limited=False, fromTable=None):
diff --git a/lib/core/dump.py b/lib/core/dump.py
index e38a73d69..41d7493ae 100644
--- a/lib/core/dump.py
+++ b/lib/core/dump.py
@@ -164,11 +164,9 @@ class Dump(object):
self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER)
def currentDb(self, data):
- if Backend.isDbms(DBMS.MAXDB):
- self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
- elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB):
self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
- elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL):
+ elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB):
self.string("current user (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
else:
self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB)
diff --git a/lib/core/settings.py b/lib/core/settings.py
index 99a02d144..324a333e4 100644
--- a/lib/core/settings.py
+++ b/lib/core/settings.py
@@ -18,7 +18,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr
# sqlmap version (...)
-VERSION = "1.4.2.30"
+VERSION = "1.4.2.31"
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)
diff --git a/lib/core/testing.py b/lib/core/testing.py
index b47c51510..be670596f 100644
--- a/lib/core/testing.py
+++ b/lib/core/testing.py
@@ -143,6 +143,11 @@ def bedTest():
"""
TESTS = (
+ # MaxDB
+ ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: TESTB", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'SAP MaxDB'", "the back-end DBMS is SAP MaxDB", "current user is DBA: True", ": 'foobar'")),
+ ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: TESTDB", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is SAP MaxDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")),
+ ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Kernel____7.9.10___Build_003-123-265-343", "current user (equivalent to database on Altibase): 'SYS'", "current user: 'DBADMIN'", "[1 column]", "| SURNAME | VARCHAR |")),
+
# Informix
("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "Database: testdb", "Table: users", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Informix'", "the back-end DBMS is Informix", "current user is DBA: True", ": 'foobar'")),
("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "current database: 'testdb'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")),
diff --git a/plugins/dbms/maxdb/enumeration.py b/plugins/dbms/maxdb/enumeration.py
index 36d626033..506d2675e 100644
--- a/plugins/dbms/maxdb/enumeration.py
+++ b/plugins/dbms/maxdb/enumeration.py
@@ -8,6 +8,7 @@ See the file 'LICENSE' for copying permission
import re
from lib.core.common import isListLike
+from lib.core.common import isTechniqueAvailable
from lib.core.common import readInput
from lib.core.common import safeSQLIdentificatorNaming
from lib.core.common import unsafeSQLIdentificatorNaming
@@ -17,6 +18,7 @@ from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.enums import DBMS
+from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapMissingMandatoryOptionException
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapUserQuitException
@@ -83,7 +85,8 @@ class Enumeration(GenericEnumeration):
for db in dbs:
query = rootQuery.inband.query % (("'%s'" % db) if db != "USER" else 'USER')
- retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.tablename' % kb.aliasName], blind=True)
+ blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION)
+ retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.tablename' % kb.aliasName], blind=blind)
if retVal:
for table in list(retVal[0].values())[0]:
@@ -204,8 +207,10 @@ class Enumeration(GenericEnumeration):
infoMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
logger.info(infoMsg)
+ blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION)
+
query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), ("'%s'" % unsafeSQLIdentificatorNaming(conf.db)) if unsafeSQLIdentificatorNaming(conf.db) != "USER" else 'USER')
- retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.columnname' % kb.aliasName, '%s.datatype' % kb.aliasName, '%s.len' % kb.aliasName], blind=True)
+ retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.columnname' % kb.aliasName, '%s.datatype' % kb.aliasName, '%s.len' % kb.aliasName], blind=blind)
if retVal:
table = {}