This commit is contained in:
Miroslav Stampar 2019-05-29 15:52:33 +02:00
parent 00435934bc
commit 95560da7c1
18 changed files with 169 additions and 3 deletions

View File

@ -41,6 +41,10 @@
<blind query="SELECT DISTINCT(privilege_type) FROM INFORMATION_SCHEMA.USER_PRIVILEGES WHERE grantee %s '%s' LIMIT %d,1" query2="SELECT select_priv,insert_priv,update_priv,delete_priv,create_priv,drop_priv,reload_priv,shutdown_priv,process_priv,file_priv,grant_priv,references_priv,index_priv,alter_priv,show_db_priv,super_priv,create_tmp_table_priv,lock_tables_priv,execute_priv,repl_slave_priv,repl_client_priv,create_view_priv,show_view_priv,create_routine_priv,alter_routine_priv,create_user_priv FROM mysql.user WHERE user='%s' LIMIT %d,1" count="SELECT COUNT(DISTINCT(privilege_type)) FROM INFORMATION_SCHEMA.USER_PRIVILEGES WHERE grantee %s '%s'" count2="SELECT COUNT(*) FROM mysql.user WHERE user='%s'"/>
</privileges>
<roles/>
<statements>
<inband query="SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST"/>
<blind query="SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY ID LIMIT %d,1" query2="SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID=%d" query3="SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST LIMIT %d,1" count="SELECT COUNT(DISTINCT(INFO)) FROM INFORMATION_SCHEMA.PROCESSLIST"/>
</statements>
<dbs>
<inband query="SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA" query2="SELECT db FROM mysql.db"/>
<blind query="SELECT DISTINCT(schema_name) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT %d,1" query2="SELECT DISTINCT(db) FROM mysql.db LIMIT %d,1" count="SELECT COUNT(DISTINCT(schema_name)) FROM INFORMATION_SCHEMA.SCHEMATA" count2="SELECT COUNT(DISTINCT(db)) FROM mysql.db"/>
@ -112,6 +116,10 @@
<blind query="SELECT (CASE WHEN usecreatedb THEN 1 ELSE 0 END),(CASE WHEN usesuper THEN 1 ELSE 0 END),(CASE WHEN usecatupd THEN 1 ELSE 0 END) FROM pg_user WHERE usename='%s' OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user WHERE usename='%s'"/>
</privileges>
<roles/>
<statements>
<inband query="SELECT query FROM pg_stat_activity WHERE query != '&lt;IDLE&gt;'"/>
<blind query="SELECT DISTINCT(query) FROM pg_stat_activity WHERE query != '&lt;IDLE&gt;' OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(query)) FROM pg_stat_activity WHERE query != '&lt;IDLE&gt;'"/>
</statements>
<dbs>
<inband query="SELECT schemaname FROM pg_tables"/>
<blind query="SELECT DISTINCT(schemaname) FROM pg_tables OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(schemaname)) FROM pg_tables"/>
@ -180,6 +188,10 @@
<!-- NOTE: in Microsoft SQL Server there is no query to enumerate DBMS users privileges -->
<privileges/>
<roles/>
<statements>
<inband query="SELECT st.text FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st"/>
<blind query="SELECT TOP 1 a.text FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) a WHERE a.text NOT IN (SELECT TOP %d b.text FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) b ORDER BY b.text) ORDER BY a.text" count="SELECT LTRIM(STR(COUNT(st.text))) FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st"/>
</statements>
<dbs>
<inband query="SELECT name FROM master..sysdatabases" query2="SELECT DB_NAME(%d)"/>
<blind query="SELECT TOP 1 name FROM master..sysdatabases WHERE name NOT IN (SELECT TOP %d name FROM master..sysdatabases ORDER BY name) ORDER BY name" count="SELECT LTRIM(STR(COUNT(name))) FROM master..sysdatabases"/>
@ -268,6 +280,10 @@
<inband query="SELECT GRANTEE,GRANTED_ROLE FROM DBA_ROLE_PRIVS" query2="SELECT USERNAME,GRANTED_ROLE FROM USER_ROLE_PRIVS" condition="GRANTEE" condition2="USERNAME"/>
<blind query="SELECT GRANTED_ROLE FROM (SELECT GRANTED_ROLE,ROWNUM AS LIMIT FROM DBA_ROLE_PRIVS WHERE GRANTEE='%s') WHERE LIMIT=%d" query2="SELECT GRANTED_ROLE FROM (SELECT GRANTED_ROLE,ROWNUM AS LIMIT FROM USER_ROLE_PRIVS WHERE USERNAME='%s') WHERE LIMIT=%d" count="SELECT COUNT(GRANTED_ROLE) FROM DBA_ROLE_PRIVS WHERE GRANTEE='%s'" count2="SELECT COUNT(GRANTED_ROLE) FROM USER_ROLE_PRIVS WHERE USERNAME='%s'"/>
</roles>
<statements>
<inband query="SELECT SQL_TEXT FROM V$SQL"/>
<blind query="SELECT SQL_TEXT FROM (SELECT SQL_TEXT,ROWNUM AS LIMIT FROM V$SQL WHERE SQL_TEXT NOT LIKE '%%SQL_TEXT%%') WHERE LIMIT=%d" count="SELECT COUNT(SQL_TEXT) FROM V$SQL WHERE SQL_TEXT NOT LIKE '%%SQL_TEXT%%'"/>
</statements>
<!-- NOTE: in Oracle schema names are the counterpart to database names on other DBMSes -->
<dbs>
<inband query="SELECT OWNER FROM (SELECT DISTINCT(OWNER) FROM SYS.ALL_TABLES)"/>
@ -332,6 +348,7 @@
<passwords/>
<privileges/>
<roles/>
<statements/>
<dbs/>
<tables>
<inband query="SELECT tbl_name FROM sqlite_master WHERE type='table'"/>
@ -392,6 +409,7 @@
<users/>
<privileges/>
<roles/>
<statements/>
<search_db/>
<search_table/>
<search_column/>
@ -435,6 +453,7 @@
<blind query="SELECT FIRST 1 SKIP %d DISTINCT(RDB$PRIVILEGE) FROM RDB$USER_PRIVILEGES WHERE RDB$USER='%s'" count="SELECT COUNT(DISTINCT(RDB$PRIVILEGE)) FROM RDB$USER_PRIVILEGES WHERE RDB$USER='%s'"/>
</privileges>
<roles/>
<statements/>
<dbs/>
<columns>
<!--<inband query="SELECT r.RDB$FIELD_NAME,CASE f.RDB$FIELD_TYPE WHEN 261 THEN 'BLOB' WHEN 14 THEN 'CHAR' WHEN 40 THEN 'CSTRING' WHEN 11 THEN 'D_FLOAT' WHEN 27 THEN 'DOUBLE' WHEN 10 THEN 'FLOAT' WHEN 16 THEN 'INT64' WHEN 8 THEN 'INTEGER' WHEN 9 THEN 'QUAD' WHEN 7 THEN 'SMALLINT' WHEN 12 THEN 'DATE' WHEN 13 THEN 'TIME' WHEN 35 THEN 'TIMESTAMP' WHEN 37 THEN 'VARCHAR' ELSE 'UNKNOWN' END AS field_type FROM RDB$RELATION_FIELDS r LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME WHERE r.RDB$RELATION_NAME='%s'"/>-->
@ -504,6 +523,7 @@
<inband query="SELECT owner,role FROM domain.roles" condition="owner"/>
<blind/>
</roles>
<statements/>
<dump_table>
<inband query="SELECT %s FROM %%s"/>
<blind query="SELECT MIN(%s) FROM %s WHERE CHR(%s)>'%s'" query2="SELECT MAX(%s) FROM %s WHERE CHR(%s) LIKE '%s'" count="SELECT COUNT(*) FROM %s" count2="SELECT COUNT(*) FROM (SELECT DISTINCT %s FROM %s) AS qq"/>
@ -549,6 +569,7 @@
<inband query="SELECT name,srid FROM master..syslogins,master..sysloginroles" condition="name"/>
<blind/>
</roles>
<statements/>
<dbs>
<inband query="SELECT name FROM master..sysdatabases"/>
<blind/>
@ -620,6 +641,7 @@
<blind query="SELECT tabschema||'.'||tabname||','||controlauth||alterauth||deleteauth||indexauth||insertauth||refauth||selectauth||updateauth FROM (SELECT ROW_NUMBER() OVER () AS LIMIT,syscat.tabauth.* FROM syscat.tabauth WHERE grantee='%s') AS qq WHERE LIMIT=%d" count="SELECT COUNT(*) FROM syscat.tabauth WHERE grantee='%s'"/>
</privileges>
<roles/>
<statements/>
<!-- NOTE: in DB2 schema names are the counterpart to database names on other DBMSes -->
<dbs>
<inband query="SELECT schemaname FROM syscat.schemata"/>
@ -690,6 +712,7 @@
</passwords>
<privileges/>
<roles/>
<statements/>
<dbs>
<blind query="SELECT LIMIT %d 1 DISTINCT(table_schem) FROM INFORMATION_SCHEMA.SYSTEM_SCHEMAS ORDER BY table_schem" count="SELECT COUNT(table_schem) FROM INFORMATION_SCHEMA.SYSTEM_SCHEMAS"/>
<inband query="SELECT table_schem FROM INFORMATION_SCHEMA.SYSTEM_SCHEMAS ORDER BY table_schem" />
@ -753,6 +776,7 @@
<passwords/>
<privileges/>
<roles/>
<statements/>
<dbs>
<inband query="SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA"/>
<blind query="SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA OFFSET %d LIMIT 1" count="SELECT COUNT(SCHEMA_NAME) FROM INFORMATION_SCHEMA.SCHEMATA"/>
@ -825,6 +849,7 @@
<blind query="SELECT USERTYPE FROM SYSUSERS WHERE USERNAME='%s'"/>
</privileges>
<roles/>
<statements/>
<dbs>
<inband query="SELECT NAME FROM SYSMASTER:SYSDATABASES"/>
<blind query="SELECT SKIP %d LIMIT 1 NAME FROM SYSMASTER:SYSDATABASES ORDER BY NAME" count="SELECT COUNT(NAME) FROM SYSMASTER:SYSDATABASES"/>

View File

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

View File

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

View File

@ -348,6 +348,7 @@ class CONTENT_TYPE:
FILE_WRITE = 23
OS_CMD = 24
REG_READ = 25
STATEMENTS = 26
class CONTENT_STATUS:
IN_PROGRESS = 0

View File

@ -139,6 +139,7 @@ optDict = {
"dumpAll": "boolean",
"search": "boolean",
"getComments": "boolean",
"getStatements": "boolean",
"db": "string",
"tbl": "string",
"col": "string",

View File

@ -18,7 +18,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
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)

View File

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

View File

@ -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 []

View File

@ -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 []

View File

@ -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 []

View File

@ -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 []

View File

@ -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 []

View File

@ -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 []

View File

@ -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 []

View File

@ -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 []

View File

@ -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 []

View File

@ -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, "<payload>") for _ in kb.data.cachedStatements]
return kb.data.cachedStatements

View File

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