diff --git a/data/xml/queries.xml b/data/xml/queries.xml
index 56983fc1e..e0c56ae74 100644
--- a/data/xml/queries.xml
+++ b/data/xml/queries.xml
@@ -41,6 +41,10 @@
+
+
+
+
@@ -112,6 +116,10 @@
+
+
+
+
@@ -180,6 +188,10 @@
+
+
+
+
@@ -268,6 +280,10 @@
+
+
+
+
@@ -332,6 +348,7 @@
+
@@ -392,6 +409,7 @@
+
@@ -435,6 +453,7 @@
+
@@ -504,6 +523,7 @@
+
@@ -549,6 +569,7 @@
+
@@ -620,6 +641,7 @@
+
@@ -690,6 +712,7 @@
+
@@ -753,6 +776,7 @@
+
@@ -825,6 +849,7 @@
+
diff --git a/lib/controller/action.py b/lib/controller/action.py
index 6c370c738..07aaeda73 100644
--- a/lib/controller/action.py
+++ b/lib/controller/action.py
@@ -72,6 +72,9 @@ def action():
if conf.getUsers:
conf.dumper.users(conf.dbmsHandler.getUsers())
+ if conf.getStatements:
+ conf.dumper.statements(conf.dbmsHandler.getStatements())
+
if conf.getPasswordHashes:
try:
conf.dumper.userSettings("database management system users password hashes", conf.dbmsHandler.getPasswordHashes(), "password hash", CONTENT_TYPE.PASSWORDS)
diff --git a/lib/core/dump.py b/lib/core/dump.py
index e79f96b2b..0a1b3979e 100644
--- a/lib/core/dump.py
+++ b/lib/core/dump.py
@@ -188,6 +188,9 @@ class Dump(object):
def users(self, users):
self.lister("database management system users", users, content_type=CONTENT_TYPE.USERS)
+ def statements(self, statements):
+ self.lister("SQL statements", statements, content_type=CONTENT_TYPE.STATEMENTS)
+
def userSettings(self, header, userSettings, subHeader, content_type=None):
self._areAdmins = set()
diff --git a/lib/core/enums.py b/lib/core/enums.py
index a13dbcd1e..bc5748de5 100644
--- a/lib/core/enums.py
+++ b/lib/core/enums.py
@@ -348,6 +348,7 @@ class CONTENT_TYPE:
FILE_WRITE = 23
OS_CMD = 24
REG_READ = 25
+ STATEMENTS = 26
class CONTENT_STATUS:
IN_PROGRESS = 0
diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py
index ccc5cfca1..c5d1c2165 100644
--- a/lib/core/optiondict.py
+++ b/lib/core/optiondict.py
@@ -139,6 +139,7 @@ optDict = {
"dumpAll": "boolean",
"search": "boolean",
"getComments": "boolean",
+ "getStatements": "boolean",
"db": "string",
"tbl": "string",
"col": "string",
diff --git a/lib/core/settings.py b/lib/core/settings.py
index 383e1d14d..8d7137dd1 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.3.5.151"
+VERSION = "1.3.5.152"
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/parse/cmdline.py b/lib/parse/cmdline.py
index 5342dffdb..fa889c9eb 100644
--- a/lib/parse/cmdline.py
+++ b/lib/parse/cmdline.py
@@ -417,6 +417,9 @@ def cmdLineParser(argv=None):
enumeration.add_option("--comments", dest="getComments", action="store_true",
help="Check for DBMS comments during enumeration")
+ enumeration.add_option("--statements", dest="getStatements", action="store_true",
+ help="Retrieve SQL statements being run on DBMS")
+
enumeration.add_option("-D", dest="db",
help="DBMS database to enumerate")
diff --git a/plugins/dbms/access/enumeration.py b/plugins/dbms/access/enumeration.py
index 3028f9366..a20c59ddf 100644
--- a/plugins/dbms/access/enumeration.py
+++ b/plugins/dbms/access/enumeration.py
@@ -76,3 +76,9 @@ class Enumeration(GenericEnumeration):
def getHostname(self):
warnMsg = "on Microsoft Access it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+
+ def getStatements(self):
+ warnMsg = "on Microsoft Access it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/db2/enumeration.py b/plugins/dbms/db2/enumeration.py
index 3fbfa1ae0..4f29cfb64 100644
--- a/plugins/dbms/db2/enumeration.py
+++ b/plugins/dbms/db2/enumeration.py
@@ -14,3 +14,9 @@ class Enumeration(GenericEnumeration):
logger.warn(warnMsg)
return {}
+
+ def getStatements(self):
+ warnMsg = "on DB2 it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/firebird/enumeration.py b/plugins/dbms/firebird/enumeration.py
index 29f1a3852..4281f8bb6 100644
--- a/plugins/dbms/firebird/enumeration.py
+++ b/plugins/dbms/firebird/enumeration.py
@@ -36,3 +36,9 @@ class Enumeration(GenericEnumeration):
def getHostname(self):
warnMsg = "on Firebird it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+
+ def getStatements(self):
+ warnMsg = "on Firebird it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/h2/enumeration.py b/plugins/dbms/h2/enumeration.py
index abe022463..23ee0dfff 100644
--- a/plugins/dbms/h2/enumeration.py
+++ b/plugins/dbms/h2/enumeration.py
@@ -47,3 +47,9 @@ class Enumeration(GenericEnumeration):
logger.warn(warnMsg)
return {}
+
+ def getStatements(self):
+ warnMsg = "on H2 it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/hsqldb/enumeration.py b/plugins/dbms/hsqldb/enumeration.py
index 7c415cb66..2b4dcd589 100644
--- a/plugins/dbms/hsqldb/enumeration.py
+++ b/plugins/dbms/hsqldb/enumeration.py
@@ -41,3 +41,9 @@ class Enumeration(GenericEnumeration):
def getCurrentDb(self):
return HSQLDB_DEFAULT_SCHEMA
+
+ def getStatements(self):
+ warnMsg = "on HSQLDB it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/informix/enumeration.py b/plugins/dbms/informix/enumeration.py
index 092224c94..5b44899c6 100644
--- a/plugins/dbms/informix/enumeration.py
+++ b/plugins/dbms/informix/enumeration.py
@@ -30,3 +30,9 @@ class Enumeration(GenericEnumeration):
def search(self):
warnMsg = "on Informix search option is not available"
logger.warn(warnMsg)
+
+ def getStatements(self):
+ warnMsg = "on Informix it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/maxdb/enumeration.py b/plugins/dbms/maxdb/enumeration.py
index 146762d52..53fd81c84 100644
--- a/plugins/dbms/maxdb/enumeration.py
+++ b/plugins/dbms/maxdb/enumeration.py
@@ -230,3 +230,9 @@ class Enumeration(GenericEnumeration):
def getHostname(self):
warnMsg = "on SAP MaxDB it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+
+ def getStatements(self):
+ warnMsg = "on SAP MaxDB it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/sqlite/enumeration.py b/plugins/dbms/sqlite/enumeration.py
index c596318ba..4812f57a0 100644
--- a/plugins/dbms/sqlite/enumeration.py
+++ b/plugins/dbms/sqlite/enumeration.py
@@ -61,3 +61,9 @@ class Enumeration(GenericEnumeration):
def getHostname(self):
warnMsg = "on SQLite it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+
+ def getStatements(self):
+ warnMsg = "on SQLite it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/dbms/sybase/enumeration.py b/plugins/dbms/sybase/enumeration.py
index faccae6e7..19e3532f8 100644
--- a/plugins/dbms/sybase/enumeration.py
+++ b/plugins/dbms/sybase/enumeration.py
@@ -316,3 +316,9 @@ class Enumeration(GenericEnumeration):
def getHostname(self):
warnMsg = "on Sybase it is not possible to enumerate the hostname"
logger.warn(warnMsg)
+
+ def getStatements(self):
+ warnMsg = "on Sybase it is not possible to enumerate the SQL statements"
+ logger.warn(warnMsg)
+
+ return []
diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py
index b9753aa90..0c4ed0f16 100644
--- a/plugins/generic/databases.py
+++ b/plugins/generic/databases.py
@@ -44,6 +44,7 @@ from lib.core.exception import SqlmapMissingMandatoryOptionException
from lib.core.exception import SqlmapNoneDataException
from lib.core.exception import SqlmapUserQuitException
from lib.core.settings import CURRENT_DB
+from lib.core.settings import REFLECTED_VALUE_MARKER
from lib.request import inject
from lib.techniques.union.use import unionUse
from lib.utils.brute import columnExists
@@ -62,6 +63,7 @@ class Databases:
kb.data.cachedColumns = {}
kb.data.cachedCounts = {}
kb.data.dumpedTable = {}
+ kb.data.cachedStatements = []
def getCurrentDb(self):
infoMsg = "fetching current database"
@@ -142,9 +144,10 @@ class Databases:
query = rootQuery.blind.query2 % index
else:
query = rootQuery.blind.query % index
+
db = unArrayizeValue(inject.getValue(query, union=False, error=False))
- if db:
+ if not isNoneValue(db):
kb.data.cachedDbs.append(safeSQLIdentificatorNaming(db))
if not kb.data.cachedDbs and Backend.isDbms(DBMS.MSSQL):
@@ -375,6 +378,7 @@ class Databases:
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(db), index)
table = unArrayizeValue(inject.getValue(query, union=False, error=False))
+
if not isNoneValue(table):
kb.hintValue = table
table = safeSQLIdentificatorNaming(table, True)
@@ -761,6 +765,7 @@ class Databases:
while True:
query = rootQuery.blind.query3 % (conf.db, unsafeSQLIdentificatorNaming(tbl), index)
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
+
if isNoneValue(value) or value == " ":
break
else:
@@ -834,8 +839,8 @@ class Databases:
query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl), column)
colType = unArrayizeValue(inject.getValue(query, union=False, error=False))
-
key = int(colType) if hasattr(colType, "isdigit") and colType.isdigit() else colType
+
if Backend.isDbms(DBMS.FIREBIRD):
colType = FIREBIRD_TYPES.get(key, colType)
elif Backend.isDbms(DBMS.INFORMIX):
@@ -960,3 +965,70 @@ class Databases:
self._tableGetCount(db, table)
return kb.data.cachedCounts
+
+ def getStatements(self):
+ infoMsg = "fetching SQL statements"
+ logger.info(infoMsg)
+
+ rootQuery = queries[Backend.getIdentifiedDbms()].statements
+
+ if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
+ query = rootQuery.inband.query
+
+ while True:
+ values = inject.getValue(query, blind=False, time=False)
+
+ if not isNoneValue(values):
+ kb.data.cachedStatements = []
+ for value in arrayizeValue(values):
+ value = (unArrayizeValue(value) or "").strip()
+ if not isNoneValue(value):
+ kb.data.cachedStatements.append(value.strip())
+
+ elif Backend.isDbms(DBMS.PGSQL) and "current_query" not in query:
+ query = query.replace("query", "current_query")
+ continue
+
+ break
+
+ if not kb.data.cachedStatements and isInferenceAvailable() and not conf.direct:
+ infoMsg = "fetching number of statements"
+ logger.info(infoMsg)
+
+ query = rootQuery.blind.count
+ count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
+
+ if count == 0:
+ return kb.data.cachedStatements
+ elif not isNumPosStrValue(count):
+ errMsg = "unable to retrieve the number of statements"
+ raise SqlmapNoneDataException(errMsg)
+
+ plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2)
+ indexRange = getLimitRange(count, plusOne=plusOne)
+
+ for index in indexRange:
+ value = None
+
+ if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): # case with multiple processes
+ query = rootQuery.blind.query3 % index
+ identifier = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT))
+
+ if not isNoneValue(identifier):
+ query = rootQuery.blind.query2 % identifier
+ value = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT))
+
+ if isNoneValue(value):
+ query = rootQuery.blind.query % index
+ value = unArrayizeValue(inject.getValue(query, union=False, error=False))
+
+ if not isNoneValue(value):
+ kb.data.cachedStatements.append(value)
+
+ if not kb.data.cachedStatements:
+ errMsg = "unable to retrieve the statements"
+ logger.error(errMsg)
+ else:
+ kb.data.cachedStatements = [_.replace(REFLECTED_VALUE_MARKER, "") for _ in kb.data.cachedStatements]
+
+ return kb.data.cachedStatements
\ No newline at end of file
diff --git a/sqlmap.conf b/sqlmap.conf
index e83e09e80..b3056cc6f 100644
--- a/sqlmap.conf
+++ b/sqlmap.conf
@@ -496,6 +496,10 @@ search = False
# Valid: True or False
getComments = False
+# Retrieve SQL statements being run on database management system.
+# Valid: True or False
+getStatements = False
+
# Back-end database management system database to enumerate.
db =