mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2024-11-25 11:03:47 +03:00
Added --count switch to count the number of entries for a specific table (when -T is provided), all database's tables (when only -D is provided) or all databases' tables when neither -D nor -T are provided
This commit is contained in:
parent
529595fd85
commit
a5968fff3e
|
@ -99,6 +99,9 @@ def action():
|
||||||
if conf.getColumns:
|
if conf.getColumns:
|
||||||
conf.dumper.dbTableColumns(conf.dbmsHandler.getColumns())
|
conf.dumper.dbTableColumns(conf.dbmsHandler.getColumns())
|
||||||
|
|
||||||
|
if conf.getCount:
|
||||||
|
conf.dumper.dbTablesCount(conf.dbmsHandler.getCount())
|
||||||
|
|
||||||
if conf.commonColumns:
|
if conf.commonColumns:
|
||||||
conf.dumper.dbTableColumns(columnExists(paths.COMMON_COLUMNS))
|
conf.dumper.dbTableColumns(columnExists(paths.COMMON_COLUMNS))
|
||||||
|
|
||||||
|
|
|
@ -2527,17 +2527,20 @@ def safeSQLIdentificatorNaming(name, isTable=False):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
retVal = name
|
retVal = name
|
||||||
|
|
||||||
if isinstance(name, basestring):
|
if isinstance(name, basestring):
|
||||||
if isTable and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and '.' not in name:
|
if isTable and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and '.' not in name:
|
||||||
name = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, name)
|
name = "%s.%s" % (DEFAULT_MSSQL_SCHEMA, name)
|
||||||
|
|
||||||
parts = name.split('.')
|
parts = name.split('.')
|
||||||
|
|
||||||
for i in range(len(parts)):
|
for i in range(len(parts)):
|
||||||
if not re.match(r"\A[A-Za-z0-9_]+\Z", parts[i]):
|
if not re.match(r"\A[A-Za-z0-9_]+\Z", parts[i]):
|
||||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS):
|
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS):
|
||||||
parts[i] = "`%s`" % parts[i].strip("`")
|
parts[i] = "`%s`" % parts[i].strip("`")
|
||||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.PGSQL):
|
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.PGSQL):
|
||||||
parts[i] = "\"%s\"" % parts[i].strip("\"")
|
parts[i] = "\"%s\"" % parts[i].strip("\"")
|
||||||
|
|
||||||
retVal = ".".join(parts)
|
retVal = ".".join(parts)
|
||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
|
|
@ -211,11 +211,11 @@ class Dump:
|
||||||
maxlength2 = max(maxlength2, len(colType))
|
maxlength2 = max(maxlength2, len(colType))
|
||||||
|
|
||||||
maxlength1 = max(maxlength1, len("COLUMN"))
|
maxlength1 = max(maxlength1, len("COLUMN"))
|
||||||
lines1 = "-" * (int(maxlength1) + 2)
|
lines1 = "-" * (maxlength1 + 2)
|
||||||
|
|
||||||
if colType is not None:
|
if colType is not None:
|
||||||
maxlength2 = max(maxlength2, len("TYPE"))
|
maxlength2 = max(maxlength2, len("TYPE"))
|
||||||
lines2 = "-" * (int(maxlength2) + 2)
|
lines2 = "-" * (maxlength2 + 2)
|
||||||
|
|
||||||
self.__write("Database: %s\nTable: %s" % (db, table))
|
self.__write("Database: %s\nTable: %s" % (db, table))
|
||||||
|
|
||||||
|
@ -256,6 +256,48 @@ class Dump:
|
||||||
else:
|
else:
|
||||||
self.__write("+%s+\n" % lines1)
|
self.__write("+%s+\n" % lines1)
|
||||||
|
|
||||||
|
def dbTablesCount(self, dbTables):
|
||||||
|
if isinstance(dbTables, dict) and len(dbTables) > 0:
|
||||||
|
maxlength1 = len("Table")
|
||||||
|
maxlength2 = len("Entries")
|
||||||
|
|
||||||
|
for ctables in dbTables.values():
|
||||||
|
for tables in ctables.values():
|
||||||
|
for table in tables:
|
||||||
|
maxlength1 = max(maxlength1, len(normalizeUnicode(table) or str(table)))
|
||||||
|
|
||||||
|
for db, counts in dbTables.items():
|
||||||
|
self.__write("Database: %s" % db)
|
||||||
|
|
||||||
|
lines1 = "-" * (maxlength1 + 2)
|
||||||
|
blank1 = " " * (maxlength1 - len("Table"))
|
||||||
|
lines2 = "-" * (maxlength2 + 2)
|
||||||
|
blank2 = " " * (maxlength2 - len("Entries"))
|
||||||
|
|
||||||
|
self.__write("+%s+%s+" % (lines1, lines2))
|
||||||
|
self.__write("| Table%s | Entries%s |" % (blank1, blank2))
|
||||||
|
self.__write("+%s+%s+" % (lines1, lines2))
|
||||||
|
|
||||||
|
sortedCounts = counts.keys()
|
||||||
|
sortedCounts.sort(reverse=True)
|
||||||
|
|
||||||
|
for count in sortedCounts:
|
||||||
|
tables = counts[count]
|
||||||
|
|
||||||
|
if count is None:
|
||||||
|
count = "Unknown"
|
||||||
|
|
||||||
|
tables.sort(key=lambda x: x.lower() if isinstance(x, basestring) else x)
|
||||||
|
|
||||||
|
for table in tables:
|
||||||
|
blank1 = " " * (maxlength1 - len(normalizeUnicode(table) or str(table)))
|
||||||
|
blank2 = " " * (maxlength2 - len(str(count)))
|
||||||
|
self.__write("| %s%s | %d%s |" % (table, blank1, count, blank2))
|
||||||
|
|
||||||
|
self.__write("+%s+%s+\n" % (lines1, lines2))
|
||||||
|
else:
|
||||||
|
logger.error("unable to retrieve the number of entries for any table")
|
||||||
|
|
||||||
def dbTableValues(self, tableValues):
|
def dbTableValues(self, tableValues):
|
||||||
replication = None
|
replication = None
|
||||||
rtable = None
|
rtable = None
|
||||||
|
|
|
@ -93,6 +93,7 @@ optDict = {
|
||||||
"getTables": ("boolean", "Tables"),
|
"getTables": ("boolean", "Tables"),
|
||||||
"getColumns": ("boolean", "Columns"),
|
"getColumns": ("boolean", "Columns"),
|
||||||
"getSchema": "boolean",
|
"getSchema": "boolean",
|
||||||
|
"getCount": "boolean",
|
||||||
"dumpTable": "boolean",
|
"dumpTable": "boolean",
|
||||||
"dumpAll": "boolean",
|
"dumpAll": "boolean",
|
||||||
"search": "boolean",
|
"search": "boolean",
|
||||||
|
|
|
@ -279,6 +279,9 @@ def cmdLineParser():
|
||||||
enumeration.add_option("--schema", dest="getSchema", action="store_true",
|
enumeration.add_option("--schema", dest="getSchema", action="store_true",
|
||||||
default=False, help="Enumerate DBMS schema")
|
default=False, help="Enumerate DBMS schema")
|
||||||
|
|
||||||
|
enumeration.add_option("--count", dest="getCount", action="store_true",
|
||||||
|
default=False, help="Retrieve number of entries for table(s)")
|
||||||
|
|
||||||
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
|
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
|
||||||
default=False, help="Dump DBMS database table entries")
|
default=False, help="Dump DBMS database table entries")
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ class Enumeration:
|
||||||
kb.data.cachedDbs = []
|
kb.data.cachedDbs = []
|
||||||
kb.data.cachedTables = {}
|
kb.data.cachedTables = {}
|
||||||
kb.data.cachedColumns = {}
|
kb.data.cachedColumns = {}
|
||||||
|
kb.data.cachedCounts = {}
|
||||||
kb.data.dumpedTable = {}
|
kb.data.dumpedTable = {}
|
||||||
kb.data.processChar = None
|
kb.data.processChar = None
|
||||||
self.alwaysRetrieveSqlOutput = False
|
self.alwaysRetrieveSqlOutput = False
|
||||||
|
@ -839,6 +840,7 @@ class Enumeration:
|
||||||
for db, table in value:
|
for db, table in value:
|
||||||
db = safeSQLIdentificatorNaming(db)
|
db = safeSQLIdentificatorNaming(db)
|
||||||
table = safeSQLIdentificatorNaming(table, True)
|
table = safeSQLIdentificatorNaming(table, True)
|
||||||
|
|
||||||
if not kb.data.cachedTables.has_key(db):
|
if not kb.data.cachedTables.has_key(db):
|
||||||
kb.data.cachedTables[db] = [table]
|
kb.data.cachedTables[db] = [table]
|
||||||
else:
|
else:
|
||||||
|
@ -885,6 +887,7 @@ class Enumeration:
|
||||||
query = rootQuery.blind.query % index
|
query = rootQuery.blind.query % index
|
||||||
else:
|
else:
|
||||||
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(db), index)
|
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(db), index)
|
||||||
|
|
||||||
table = inject.getValue(query, inband=False, error=False)
|
table = inject.getValue(query, inband=False, error=False)
|
||||||
kb.hintValue = table
|
kb.hintValue = table
|
||||||
table = safeSQLIdentificatorNaming(table, True)
|
table = safeSQLIdentificatorNaming(table, True)
|
||||||
|
@ -1174,6 +1177,56 @@ class Enumeration:
|
||||||
|
|
||||||
return kb.data.cachedColumns
|
return kb.data.cachedColumns
|
||||||
|
|
||||||
|
def __tableGetCount(self, db, table):
|
||||||
|
query = "SELECT COUNT(*) FROM %s.%s" % (safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(table, True))
|
||||||
|
count = inject.getValue(query, expected=EXPECTED.INT, charsetType=2)
|
||||||
|
|
||||||
|
if count is not None and isinstance(count, basestring) and count.isdigit():
|
||||||
|
if unsafeSQLIdentificatorNaming(db) not in kb.data.cachedCounts:
|
||||||
|
kb.data.cachedCounts[unsafeSQLIdentificatorNaming(db)] = {}
|
||||||
|
|
||||||
|
if int(count) in kb.data.cachedCounts[unsafeSQLIdentificatorNaming(db)]:
|
||||||
|
kb.data.cachedCounts[unsafeSQLIdentificatorNaming(db)][int(count)].append(unsafeSQLIdentificatorNaming(table))
|
||||||
|
else:
|
||||||
|
kb.data.cachedCounts[unsafeSQLIdentificatorNaming(db)][int(count)] = [unsafeSQLIdentificatorNaming(table)]
|
||||||
|
|
||||||
|
def getCount(self):
|
||||||
|
if not conf.tbl:
|
||||||
|
warnMsg = "missing table parameter, sqlmap will retrieve "
|
||||||
|
warnMsg += "the number of entries for all database "
|
||||||
|
warnMsg += "management system databases' tables"
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
elif "." in conf.tbl:
|
||||||
|
if not conf.db:
|
||||||
|
conf.db, conf.tbl = conf.tbl.split(".")
|
||||||
|
|
||||||
|
if conf.tbl is not None and conf.db is None:
|
||||||
|
warnMsg = "missing database parameter, sqlmap is going to "
|
||||||
|
warnMsg += "use the current database to retrieve the "
|
||||||
|
warnMsg += "number of entries for table '%s'" % conf.tbl
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
conf.db = self.getCurrentDb()
|
||||||
|
|
||||||
|
self.forceDbmsEnum()
|
||||||
|
|
||||||
|
if conf.db:
|
||||||
|
conf.db = safeSQLIdentificatorNaming(conf.db)
|
||||||
|
|
||||||
|
if conf.tbl:
|
||||||
|
for table in conf.tbl.split(","):
|
||||||
|
table = safeSQLIdentificatorNaming(table, True)
|
||||||
|
self.__tableGetCount(conf.db, table)
|
||||||
|
else:
|
||||||
|
self.getTables()
|
||||||
|
|
||||||
|
for db, tables in kb.data.cachedTables.items():
|
||||||
|
for table in tables:
|
||||||
|
self.__tableGetCount(db, table)
|
||||||
|
|
||||||
|
return kb.data.cachedCounts
|
||||||
|
|
||||||
def __pivotDumpTable(self, table, colList, count=None, blind=True):
|
def __pivotDumpTable(self, table, colList, count=None, blind=True):
|
||||||
lengths = {}
|
lengths = {}
|
||||||
entries = {}
|
entries = {}
|
||||||
|
@ -1580,7 +1633,6 @@ class Enumeration:
|
||||||
infoMsg = "skipping table '%s'" % table
|
infoMsg = "skipping table '%s'" % table
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
|
||||||
def dumpFoundColumn(self, dbs, foundCols, colConsider):
|
def dumpFoundColumn(self, dbs, foundCols, colConsider):
|
||||||
if not dbs:
|
if not dbs:
|
||||||
warnMsg = "no databases have tables containing any of the "
|
warnMsg = "no databases have tables containing any of the "
|
||||||
|
|
|
@ -314,6 +314,10 @@ getColumns = False
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
getSchema = False
|
getSchema = False
|
||||||
|
|
||||||
|
# Retrieve number of entries for table(s).
|
||||||
|
# Valid: True or False
|
||||||
|
getCount = False
|
||||||
|
|
||||||
# Dump back-end database management system database table entries.
|
# Dump back-end database management system database table entries.
|
||||||
# Requires: tbl and/or col
|
# Requires: tbl and/or col
|
||||||
# Optional: db
|
# Optional: db
|
||||||
|
|
Loading…
Reference in New Issue
Block a user