Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/plugins/generic/databases.py
3553 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import re
9
10
from lib.core.agent import agent
11
from lib.core.common import arrayizeValue
12
from lib.core.common import Backend
13
from lib.core.common import filterNone
14
from lib.core.common import filterPairValues
15
from lib.core.common import flattenValue
16
from lib.core.common import getLimitRange
17
from lib.core.common import isInferenceAvailable
18
from lib.core.common import isListLike
19
from lib.core.common import isNoneValue
20
from lib.core.common import isNumPosStrValue
21
from lib.core.common import isTechniqueAvailable
22
from lib.core.common import parseSqliteTableSchema
23
from lib.core.common import popValue
24
from lib.core.common import pushValue
25
from lib.core.common import readInput
26
from lib.core.common import safeSQLIdentificatorNaming
27
from lib.core.common import safeStringFormat
28
from lib.core.common import singleTimeLogMessage
29
from lib.core.common import singleTimeWarnMessage
30
from lib.core.common import unArrayizeValue
31
from lib.core.common import unsafeSQLIdentificatorNaming
32
from lib.core.data import conf
33
from lib.core.data import kb
34
from lib.core.data import logger
35
from lib.core.data import paths
36
from lib.core.data import queries
37
from lib.core.decorators import stackedmethod
38
from lib.core.dicts import ALTIBASE_TYPES
39
from lib.core.dicts import FIREBIRD_TYPES
40
from lib.core.dicts import INFORMIX_TYPES
41
from lib.core.enums import CHARSET_TYPE
42
from lib.core.enums import DBMS
43
from lib.core.enums import EXPECTED
44
from lib.core.enums import FORK
45
from lib.core.enums import PAYLOAD
46
from lib.core.exception import SqlmapMissingMandatoryOptionException
47
from lib.core.exception import SqlmapNoneDataException
48
from lib.core.exception import SqlmapUserQuitException
49
from lib.core.settings import CURRENT_DB
50
from lib.core.settings import METADB_SUFFIX
51
from lib.core.settings import PLUS_ONE_DBMSES
52
from lib.core.settings import REFLECTED_VALUE_MARKER
53
from lib.core.settings import UPPER_CASE_DBMSES
54
from lib.core.settings import VERTICA_DEFAULT_SCHEMA
55
from lib.request import inject
56
from lib.utils.brute import columnExists
57
from lib.utils.brute import tableExists
58
from thirdparty import six
59
60
class Databases(object):
61
"""
62
This class defines databases' enumeration functionalities for plugins.
63
"""
64
65
def __init__(self):
66
kb.data.currentDb = ""
67
kb.data.cachedDbs = []
68
kb.data.cachedTables = {}
69
kb.data.cachedColumns = {}
70
kb.data.cachedCounts = {}
71
kb.data.dumpedTable = {}
72
kb.data.cachedStatements = []
73
74
def getCurrentDb(self):
75
infoMsg = "fetching current database"
76
logger.info(infoMsg)
77
78
query = queries[Backend.getIdentifiedDbms()].current_db.query
79
80
if not kb.data.currentDb:
81
kb.data.currentDb = unArrayizeValue(inject.getValue(query, safeCharEncode=False))
82
83
if not kb.data.currentDb and Backend.isDbms(DBMS.VERTICA):
84
kb.data.currentDb = VERTICA_DEFAULT_SCHEMA
85
86
if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.SNOWFLAKE):
87
warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms()
88
warnMsg += "schema names for enumeration as the counterpart to database "
89
warnMsg += "names on other DBMSes"
90
singleTimeWarnMessage(warnMsg)
91
elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.CUBRID):
92
warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms()
93
warnMsg += "user names for enumeration as the counterpart to database "
94
warnMsg += "names on other DBMSes"
95
singleTimeWarnMessage(warnMsg)
96
97
return kb.data.currentDb
98
99
def getDbs(self):
100
if len(kb.data.cachedDbs) > 0:
101
return kb.data.cachedDbs
102
103
infoMsg = None
104
105
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
106
warnMsg = "information_schema not available, "
107
warnMsg += "back-end DBMS is MySQL < 5. database "
108
warnMsg += "names will be fetched from 'mysql' database"
109
logger.warning(warnMsg)
110
111
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.SNOWFLAKE):
112
warnMsg = "schema names are going to be used on %s " % Backend.getIdentifiedDbms()
113
warnMsg += "for enumeration as the counterpart to database "
114
warnMsg += "names on other DBMSes"
115
logger.warning(warnMsg)
116
117
infoMsg = "fetching database (schema) names"
118
119
elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.CUBRID):
120
warnMsg = "user names are going to be used on %s " % Backend.getIdentifiedDbms()
121
warnMsg += "for enumeration as the counterpart to database "
122
warnMsg += "names on other DBMSes"
123
logger.warning(warnMsg)
124
125
infoMsg = "fetching database (user) names"
126
127
else:
128
infoMsg = "fetching database names"
129
130
if infoMsg:
131
logger.info(infoMsg)
132
133
rootQuery = queries[Backend.getIdentifiedDbms()].dbs
134
135
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
136
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
137
query = rootQuery.inband.query2
138
else:
139
query = rootQuery.inband.query
140
values = inject.getValue(query, blind=False, time=False)
141
142
if not isNoneValue(values):
143
kb.data.cachedDbs = arrayizeValue(values)
144
145
if not kb.data.cachedDbs and isInferenceAvailable() and not conf.direct:
146
infoMsg = "fetching number of databases"
147
logger.info(infoMsg)
148
149
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
150
query = rootQuery.blind.count2
151
else:
152
query = rootQuery.blind.count
153
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
154
155
if not isNumPosStrValue(count):
156
errMsg = "unable to retrieve the number of databases"
157
logger.error(errMsg)
158
else:
159
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
160
indexRange = getLimitRange(count, plusOne=plusOne)
161
162
for index in indexRange:
163
if Backend.isDbms(DBMS.SYBASE):
164
query = rootQuery.blind.query % (kb.data.cachedDbs[-1] if kb.data.cachedDbs else " ")
165
elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
166
query = rootQuery.blind.query2 % index
167
else:
168
query = rootQuery.blind.query % index
169
170
db = unArrayizeValue(inject.getValue(query, union=False, error=False))
171
172
if not isNoneValue(db):
173
kb.data.cachedDbs.append(safeSQLIdentificatorNaming(db))
174
175
if not kb.data.cachedDbs and Backend.isDbms(DBMS.MSSQL):
176
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
177
blinds = (False, True)
178
else:
179
blinds = (True,)
180
181
for blind in blinds:
182
count = 0
183
kb.data.cachedDbs = []
184
while True:
185
query = rootQuery.inband.query2 % count
186
value = unArrayizeValue(inject.getValue(query, blind=blind))
187
if not (value or "").strip():
188
break
189
else:
190
kb.data.cachedDbs.append(value)
191
count += 1
192
if kb.data.cachedDbs:
193
break
194
195
if not kb.data.cachedDbs:
196
infoMsg = "falling back to current database"
197
logger.info(infoMsg)
198
self.getCurrentDb()
199
200
if kb.data.currentDb:
201
kb.data.cachedDbs = [kb.data.currentDb]
202
else:
203
errMsg = "unable to retrieve the database names"
204
raise SqlmapNoneDataException(errMsg)
205
else:
206
kb.data.cachedDbs.sort()
207
208
if kb.data.cachedDbs:
209
kb.data.cachedDbs = [_ for _ in set(flattenValue(kb.data.cachedDbs)) if _]
210
211
return kb.data.cachedDbs
212
213
def getTables(self, bruteForce=None):
214
if len(kb.data.cachedTables) > 0:
215
return kb.data.cachedTables
216
217
self.forceDbmsEnum()
218
219
if bruteForce is None:
220
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
221
warnMsg = "information_schema not available, "
222
warnMsg += "back-end DBMS is MySQL < 5.0"
223
logger.warning(warnMsg)
224
bruteForce = True
225
226
elif Backend.getIdentifiedDbms() in (DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA):
227
bruteForce = True
228
229
elif Backend.getIdentifiedDbms() in (DBMS.ACCESS,):
230
try:
231
tables = self.getTables(False)
232
except SqlmapNoneDataException:
233
tables = None
234
235
if not tables:
236
warnMsg = "cannot retrieve table names, "
237
warnMsg += "back-end DBMS is %s" % Backend.getIdentifiedDbms()
238
logger.warning(warnMsg)
239
bruteForce = True
240
else:
241
return tables
242
243
if conf.db == CURRENT_DB:
244
conf.db = self.getCurrentDb()
245
246
if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
247
conf.db = conf.db.upper()
248
249
if conf.db:
250
dbs = conf.db.split(',')
251
else:
252
dbs = self.getDbs()
253
254
dbs = [_ for _ in dbs if _ and _.strip()]
255
256
for db in dbs:
257
dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db)
258
259
if bruteForce:
260
resumeAvailable = False
261
262
for db, table in kb.brute.tables:
263
if db == conf.db:
264
resumeAvailable = True
265
break
266
267
if resumeAvailable and not conf.freshQueries:
268
for db, table in kb.brute.tables:
269
if db == conf.db:
270
if conf.db not in kb.data.cachedTables:
271
kb.data.cachedTables[conf.db] = [table]
272
else:
273
kb.data.cachedTables[conf.db].append(table)
274
275
return kb.data.cachedTables
276
277
message = "do you want to use common table existence check? %s " % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]")
278
choice = readInput(message, default='Y' if 'Y' in message else 'N').upper()
279
280
if choice == 'N':
281
return
282
elif choice == 'Q':
283
raise SqlmapUserQuitException
284
else:
285
return tableExists(paths.COMMON_TABLES)
286
287
infoMsg = "fetching tables for database"
288
infoMsg += "%s: '%s'" % ("s" if len(dbs) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(unArrayizeValue(db)) for db in sorted(dbs)))
289
logger.info(infoMsg)
290
291
rootQuery = queries[Backend.getIdentifiedDbms()].tables
292
293
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
294
values = []
295
296
for query, condition in ((rootQuery.inband.query, getattr(rootQuery.inband, "condition", None)), (getattr(rootQuery.inband, "query2", None), getattr(rootQuery.inband, "condition2", None))):
297
if not isNoneValue(values) or not query:
298
break
299
300
if condition:
301
if not Backend.isDbms(DBMS.SQLITE):
302
query += " WHERE %s" % condition
303
304
if conf.excludeSysDbs:
305
infoMsg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in self.excludeDbsList))
306
logger.info(infoMsg)
307
query += " IN (%s)" % ','.join("'%s'" % unsafeSQLIdentificatorNaming(db) for db in sorted(dbs) if db not in self.excludeDbsList)
308
else:
309
query += " IN (%s)" % ','.join("'%s'" % unsafeSQLIdentificatorNaming(db) for db in sorted(dbs))
310
311
if len(dbs) < 2 and ("%s," % condition) in query:
312
query = query.replace("%s," % condition, "", 1)
313
314
if query:
315
values = inject.getValue(query, blind=False, time=False)
316
317
if not isNoneValue(values):
318
values = [_ for _ in arrayizeValue(values) if _]
319
320
if len(values) > 0 and not isListLike(values[0]):
321
values = [(dbs[0], _) for _ in values]
322
323
for db, table in filterPairValues(values):
324
table = unArrayizeValue(table)
325
326
if not isNoneValue(table):
327
db = safeSQLIdentificatorNaming(db)
328
table = safeSQLIdentificatorNaming(table, True).strip()
329
330
if conf.getComments:
331
_ = queries[Backend.getIdentifiedDbms()].table_comment
332
if hasattr(_, "query"):
333
if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE):
334
query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper()))
335
else:
336
query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table))
337
338
comment = unArrayizeValue(inject.getValue(query, blind=False, time=False))
339
if not isNoneValue(comment):
340
infoMsg = "retrieved comment '%s' for table '%s'" % (comment, unsafeSQLIdentificatorNaming(table))
341
if METADB_SUFFIX not in db:
342
infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(db)
343
logger.info(infoMsg)
344
else:
345
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
346
warnMsg += "possible to get table comments"
347
singleTimeWarnMessage(warnMsg)
348
349
if db not in kb.data.cachedTables:
350
kb.data.cachedTables[db] = [table]
351
else:
352
kb.data.cachedTables[db].append(table)
353
354
if not kb.data.cachedTables and isInferenceAvailable() and not conf.direct:
355
for db in dbs:
356
if conf.excludeSysDbs and db in self.excludeDbsList:
357
infoMsg = "skipping system database '%s'" % unsafeSQLIdentificatorNaming(db)
358
logger.info(infoMsg)
359
continue
360
361
if conf.exclude and re.search(conf.exclude, db, re.I) is not None:
362
infoMsg = "skipping database '%s'" % unsafeSQLIdentificatorNaming(db)
363
singleTimeLogMessage(infoMsg)
364
continue
365
366
for _query, _count in ((rootQuery.blind.query, rootQuery.blind.count), (getattr(rootQuery.blind, "query2", None), getattr(rootQuery.blind, "count2", None))):
367
if _query is None:
368
break
369
370
infoMsg = "fetching number of tables for "
371
infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(db)
372
logger.info(infoMsg)
373
374
if Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB):
375
query = _count % unsafeSQLIdentificatorNaming(db)
376
else:
377
query = _count
378
379
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
380
381
if count == 0:
382
warnMsg = "database '%s' " % unsafeSQLIdentificatorNaming(db)
383
warnMsg += "appears to be empty"
384
logger.warning(warnMsg)
385
break
386
387
elif not isNumPosStrValue(count):
388
warnMsg = "unable to retrieve the number of "
389
warnMsg += "tables for database '%s'" % unsafeSQLIdentificatorNaming(db)
390
singleTimeWarnMessage(warnMsg)
391
continue
392
393
tables = []
394
395
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
396
indexRange = getLimitRange(count, plusOne=plusOne)
397
398
for index in indexRange:
399
if Backend.isDbms(DBMS.SYBASE):
400
query = _query % (db, (kb.data.cachedTables[-1] if kb.data.cachedTables else " "))
401
elif Backend.getIdentifiedDbms() in (DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB):
402
query = _query % (kb.data.cachedTables[-1] if kb.data.cachedTables else " ")
403
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD):
404
query = _query % index
405
elif Backend.getIdentifiedDbms() in (DBMS.HSQLDB, DBMS.INFORMIX, DBMS.FRONTBASE, DBMS.VIRTUOSO):
406
query = _query % (index, unsafeSQLIdentificatorNaming(db))
407
else:
408
query = _query % (unsafeSQLIdentificatorNaming(db), index)
409
410
table = unArrayizeValue(inject.getValue(query, union=False, error=False))
411
412
if not isNoneValue(table):
413
kb.hintValue = table
414
table = safeSQLIdentificatorNaming(table, True)
415
tables.append(table)
416
417
if tables:
418
kb.data.cachedTables[db] = tables
419
420
if conf.getComments:
421
for table in tables:
422
_ = queries[Backend.getIdentifiedDbms()].table_comment
423
if hasattr(_, "query"):
424
if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE):
425
query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper()))
426
else:
427
query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table))
428
429
comment = unArrayizeValue(inject.getValue(query, union=False, error=False))
430
if not isNoneValue(comment):
431
infoMsg = "retrieved comment '%s' for table '%s'" % (comment, unsafeSQLIdentificatorNaming(table))
432
if METADB_SUFFIX not in db:
433
infoMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(db)
434
logger.info(infoMsg)
435
else:
436
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
437
warnMsg += "possible to get table comments"
438
singleTimeWarnMessage(warnMsg)
439
440
break
441
else:
442
warnMsg = "unable to retrieve the table names "
443
warnMsg += "for database '%s'" % unsafeSQLIdentificatorNaming(db)
444
logger.warning(warnMsg)
445
446
if isNoneValue(kb.data.cachedTables):
447
kb.data.cachedTables.clear()
448
449
if not kb.data.cachedTables:
450
errMsg = "unable to retrieve the table names for any database"
451
if bruteForce is None:
452
logger.error(errMsg)
453
return self.getTables(bruteForce=True)
454
elif not conf.search:
455
raise SqlmapNoneDataException(errMsg)
456
else:
457
for db, tables in kb.data.cachedTables.items():
458
kb.data.cachedTables[db] = sorted(tables) if tables else tables
459
460
if kb.data.cachedTables:
461
for db in kb.data.cachedTables:
462
kb.data.cachedTables[db] = list(set(kb.data.cachedTables[db]))
463
464
return kb.data.cachedTables
465
466
def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False):
467
self.forceDbmsEnum()
468
469
if conf.db is None or conf.db == CURRENT_DB:
470
if conf.db is None:
471
warnMsg = "missing database parameter. sqlmap is going "
472
warnMsg += "to use the current database to enumerate "
473
warnMsg += "table(s) columns"
474
logger.warning(warnMsg)
475
476
conf.db = self.getCurrentDb()
477
478
if not conf.db:
479
errMsg = "unable to retrieve the current "
480
errMsg += "database name"
481
raise SqlmapNoneDataException(errMsg)
482
483
elif conf.db is not None:
484
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
485
conf.db = conf.db.upper()
486
487
if ',' in conf.db:
488
errMsg = "only one database name is allowed when enumerating "
489
errMsg += "the tables' columns"
490
raise SqlmapMissingMandatoryOptionException(errMsg)
491
492
conf.db = safeSQLIdentificatorNaming(conf.db)
493
494
if conf.col:
495
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
496
conf.col = conf.col.upper()
497
498
colList = conf.col.split(',')
499
else:
500
colList = []
501
502
if conf.exclude:
503
colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None]
504
505
for col in colList:
506
colList[colList.index(col)] = safeSQLIdentificatorNaming(col)
507
508
colList = [_ for _ in colList if _]
509
510
if conf.tbl:
511
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
512
conf.tbl = conf.tbl.upper()
513
514
tblList = conf.tbl.split(',')
515
else:
516
self.getTables()
517
518
if len(kb.data.cachedTables) > 0:
519
if conf.db in kb.data.cachedTables:
520
tblList = kb.data.cachedTables[conf.db]
521
else:
522
tblList = list(six.itervalues(kb.data.cachedTables))
523
524
if tblList and isListLike(tblList[0]):
525
tblList = tblList[0]
526
527
tblList = list(tblList)
528
elif not conf.search:
529
errMsg = "unable to retrieve the tables"
530
if METADB_SUFFIX not in conf.db:
531
errMsg += " in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
532
raise SqlmapNoneDataException(errMsg)
533
else:
534
return kb.data.cachedColumns
535
536
if conf.exclude:
537
tblList = [_ for _ in tblList if re.search(conf.exclude, _, re.I) is None]
538
539
tblList = filterNone(safeSQLIdentificatorNaming(_, True) for _ in tblList)
540
541
if bruteForce is None:
542
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
543
warnMsg = "information_schema not available, "
544
warnMsg += "back-end DBMS is MySQL < 5.0"
545
logger.warning(warnMsg)
546
bruteForce = True
547
548
elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB, DBMS.RAIMA):
549
warnMsg = "cannot retrieve column names, "
550
warnMsg += "back-end DBMS is %s" % Backend.getIdentifiedDbms()
551
singleTimeWarnMessage(warnMsg)
552
bruteForce = True
553
554
if bruteForce:
555
resumeAvailable = False
556
557
for tbl in tblList:
558
for db, table, colName, colType in kb.brute.columns:
559
if db == conf.db and table == tbl:
560
resumeAvailable = True
561
break
562
563
if resumeAvailable and not (conf.freshQueries and not colList):
564
columns = {}
565
566
for column in colList:
567
columns[column] = None
568
569
for tbl in tblList:
570
for db, table, colName, colType in kb.brute.columns:
571
if db == conf.db and table == tbl:
572
columns[colName] = colType
573
574
if conf.db in kb.data.cachedColumns:
575
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns
576
else:
577
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns}
578
579
return kb.data.cachedColumns
580
581
if kb.choices.columnExists is None:
582
message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]")
583
kb.choices.columnExists = readInput(message, default='Y' if 'Y' in message else 'N').upper()
584
585
if kb.choices.columnExists == 'N':
586
if dumpMode and colList:
587
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): dict((_, None) for _ in colList)}
588
return kb.data.cachedColumns
589
else:
590
return None
591
elif kb.choices.columnExists == 'Q':
592
raise SqlmapUserQuitException
593
else:
594
return columnExists(paths.COMMON_COLUMNS)
595
596
rootQuery = queries[Backend.getIdentifiedDbms()].columns
597
condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None
598
599
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
600
for tbl in tblList:
601
if conf.db is not None and len(kb.data.cachedColumns) > 0 \
602
and conf.db in kb.data.cachedColumns and tbl in \
603
kb.data.cachedColumns[conf.db]:
604
infoMsg = "fetched table columns from "
605
infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
606
logger.info(infoMsg)
607
608
return {conf.db: kb.data.cachedColumns[conf.db]}
609
610
infoMsg = "fetching columns "
611
condQuery = ""
612
613
if len(colList) > 0:
614
if colTuple:
615
_, colCondParam = colTuple
616
infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList))
617
else:
618
colCondParam = "='%s'"
619
infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList))
620
621
condQueryStr = "%%s%s" % colCondParam
622
condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList))
623
624
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE):
625
query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
626
query += condQuery
627
628
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
629
query = re.sub("column_type", "data_type", query, flags=re.I)
630
631
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.SNOWFLAKE):
632
query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
633
query += condQuery
634
635
elif Backend.isDbms(DBMS.MSSQL):
636
query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db,
637
conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1])
638
query += condQuery.replace("[DB]", conf.db)
639
640
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD):
641
query = rootQuery.inband.query % unsafeSQLIdentificatorNaming(tbl)
642
643
elif Backend.isDbms(DBMS.INFORMIX):
644
query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))
645
query += condQuery
646
647
if dumpMode and colList:
648
values = [(_,) for _ in colList]
649
else:
650
infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl)
651
if METADB_SUFFIX not in conf.db:
652
infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
653
logger.info(infoMsg)
654
655
values = None
656
657
if values is None:
658
values = inject.getValue(query, blind=False, time=False)
659
if values and isinstance(values[0], six.string_types):
660
values = [values]
661
662
if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values):
663
index, values = 1, []
664
665
while True:
666
query = rootQuery.inband.query2 % (conf.db, unsafeSQLIdentificatorNaming(tbl), index)
667
value = unArrayizeValue(inject.getValue(query, blind=False, time=False))
668
669
if isNoneValue(value) or value == " ":
670
break
671
else:
672
values.append((value,))
673
index += 1
674
675
if Backend.isDbms(DBMS.SQLITE):
676
if dumpMode and colList:
677
if conf.db not in kb.data.cachedColumns:
678
kb.data.cachedColumns[conf.db] = {}
679
kb.data.cachedColumns[conf.db][safeSQLIdentificatorNaming(conf.tbl, True)] = dict((_, None) for _ in colList)
680
else:
681
parseSqliteTableSchema(unArrayizeValue(values))
682
683
elif not isNoneValue(values):
684
table = {}
685
columns = {}
686
687
for columnData in values:
688
if not isNoneValue(columnData):
689
columnData = [unArrayizeValue(_) for _ in columnData]
690
name = safeSQLIdentificatorNaming(columnData[0])
691
692
if name:
693
if conf.getComments:
694
_ = queries[Backend.getIdentifiedDbms()].column_comment
695
if hasattr(_, "query"):
696
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
697
query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper()))
698
else:
699
query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name))
700
701
comment = unArrayizeValue(inject.getValue(query, blind=False, time=False))
702
if not isNoneValue(comment):
703
infoMsg = "retrieved comment '%s' for column '%s'" % (comment, name)
704
logger.info(infoMsg)
705
else:
706
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
707
warnMsg += "possible to get column comments"
708
singleTimeWarnMessage(warnMsg)
709
710
if len(columnData) == 1:
711
columns[name] = None
712
else:
713
key = int(columnData[1]) if isinstance(columnData[1], six.string_types) and columnData[1].isdigit() else columnData[1]
714
if Backend.isDbms(DBMS.FIREBIRD):
715
columnData[1] = FIREBIRD_TYPES.get(key, columnData[1])
716
elif Backend.isDbms(DBMS.ALTIBASE):
717
columnData[1] = ALTIBASE_TYPES.get(key, columnData[1])
718
elif Backend.isDbms(DBMS.INFORMIX):
719
notNull = False
720
if isinstance(key, int) and key > 255:
721
key -= 256
722
notNull = True
723
columnData[1] = INFORMIX_TYPES.get(key, columnData[1])
724
if notNull:
725
columnData[1] = "%s NOT NULL" % columnData[1]
726
727
columns[name] = columnData[1]
728
729
if conf.db in kb.data.cachedColumns:
730
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns
731
else:
732
table[safeSQLIdentificatorNaming(tbl, True)] = columns
733
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
734
735
elif isInferenceAvailable() and not conf.direct:
736
for tbl in tblList:
737
if conf.db is not None and len(kb.data.cachedColumns) > 0 \
738
and conf.db in kb.data.cachedColumns and tbl in \
739
kb.data.cachedColumns[conf.db]:
740
infoMsg = "fetched table columns from "
741
infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
742
logger.info(infoMsg)
743
744
return {conf.db: kb.data.cachedColumns[conf.db]}
745
746
infoMsg = "fetching columns "
747
condQuery = ""
748
749
if len(colList) > 0:
750
if colTuple:
751
_, colCondParam = colTuple
752
infoMsg += "LIKE '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList))
753
else:
754
colCondParam = "='%s'"
755
infoMsg += "'%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList))
756
757
condQueryStr = "%%s%s" % colCondParam
758
condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList))
759
760
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE, DBMS.SNOWFLAKE):
761
query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
762
query += condQuery
763
764
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL):
765
query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
766
query += condQuery
767
768
elif Backend.isDbms(DBMS.MSSQL):
769
query = rootQuery.blind.count % (conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1])
770
query += condQuery.replace("[DB]", conf.db)
771
772
elif Backend.isDbms(DBMS.FIREBIRD):
773
query = rootQuery.blind.count % unsafeSQLIdentificatorNaming(tbl)
774
query += condQuery
775
776
elif Backend.isDbms(DBMS.INFORMIX):
777
query = rootQuery.blind.count % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))
778
query += condQuery
779
780
elif Backend.isDbms(DBMS.SQLITE):
781
if dumpMode and colList:
782
if conf.db not in kb.data.cachedColumns:
783
kb.data.cachedColumns[conf.db] = {}
784
kb.data.cachedColumns[conf.db][safeSQLIdentificatorNaming(conf.tbl, True)] = dict((_, None) for _ in colList)
785
else:
786
query = rootQuery.blind.query % unsafeSQLIdentificatorNaming(tbl)
787
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
788
parseSqliteTableSchema(unArrayizeValue(value))
789
790
return kb.data.cachedColumns
791
792
table = {}
793
columns = {}
794
795
if dumpMode and colList:
796
count = 0
797
for value in colList:
798
columns[safeSQLIdentificatorNaming(value)] = None
799
else:
800
infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl)
801
if METADB_SUFFIX not in conf.db:
802
infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
803
logger.info(infoMsg)
804
805
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
806
807
if not isNumPosStrValue(count):
808
if Backend.isDbms(DBMS.MSSQL):
809
count, index, values = 0, 1, []
810
while True:
811
query = rootQuery.blind.query3 % (conf.db, unsafeSQLIdentificatorNaming(tbl), index)
812
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
813
814
if isNoneValue(value) or value == " ":
815
break
816
else:
817
columns[safeSQLIdentificatorNaming(value)] = None
818
index += 1
819
820
if not columns:
821
errMsg = "unable to retrieve the %scolumns " % ("number of " if not Backend.isDbms(DBMS.MSSQL) else "")
822
errMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl)
823
if METADB_SUFFIX not in conf.db:
824
errMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
825
logger.error(errMsg)
826
continue
827
828
for index in getLimitRange(count):
829
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO):
830
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
831
query += condQuery
832
field = None
833
elif Backend.isDbms(DBMS.H2):
834
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
835
query = query.replace(" ORDER BY ", "%s ORDER BY " % condQuery)
836
field = None
837
elif Backend.isDbms(DBMS.MIMERSQL):
838
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
839
query = query.replace(" ORDER BY ", "%s ORDER BY " % condQuery)
840
field = None
841
elif Backend.isDbms(DBMS.SNOWFLAKE):
842
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
843
field = None
844
elif Backend.getIdentifiedDbms() in (DBMS.MONETDB, DBMS.CLICKHOUSE):
845
query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index))
846
field = None
847
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE):
848
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
849
query += condQuery
850
field = None
851
elif Backend.isDbms(DBMS.MSSQL):
852
query = rootQuery.blind.query.replace("'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1]).replace("%s", conf.db).replace("%d", str(index))
853
query += condQuery.replace("[DB]", conf.db)
854
field = condition.replace("[DB]", conf.db)
855
elif Backend.isDbms(DBMS.FIREBIRD):
856
query = rootQuery.blind.query % unsafeSQLIdentificatorNaming(tbl)
857
query += condQuery
858
field = None
859
elif Backend.isDbms(DBMS.INFORMIX):
860
query = rootQuery.blind.query % (index, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))
861
query += condQuery
862
field = condition
863
864
query = agent.limitQuery(index, query, field, field)
865
column = unArrayizeValue(inject.getValue(query, union=False, error=False))
866
867
if not isNoneValue(column):
868
if conf.getComments:
869
_ = queries[Backend.getIdentifiedDbms()].column_comment
870
if hasattr(_, "query"):
871
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
872
query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper()))
873
else:
874
query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column))
875
876
comment = unArrayizeValue(inject.getValue(query, union=False, error=False))
877
if not isNoneValue(comment):
878
infoMsg = "retrieved comment '%s' for column '%s'" % (comment, column)
879
logger.info(infoMsg)
880
else:
881
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
882
warnMsg += "possible to get column comments"
883
singleTimeWarnMessage(warnMsg)
884
885
if not onlyColNames:
886
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.VIRTUOSO, DBMS.CLICKHOUSE):
887
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db))
888
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL):
889
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper()))
890
elif Backend.isDbms(DBMS.MSSQL):
891
query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1])
892
elif Backend.isDbms(DBMS.FIREBIRD):
893
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column)
894
elif Backend.isDbms(DBMS.INFORMIX):
895
query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl), column)
896
elif Backend.isDbms(DBMS.MONETDB):
897
query = rootQuery.blind.query2 % (column, unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
898
899
colType = unArrayizeValue(inject.getValue(query, union=False, error=False))
900
key = int(colType) if hasattr(colType, "isdigit") and colType.isdigit() else colType
901
902
if Backend.isDbms(DBMS.FIREBIRD):
903
colType = FIREBIRD_TYPES.get(key, colType)
904
elif Backend.isDbms(DBMS.INFORMIX):
905
notNull = False
906
if isinstance(key, int) and key > 255:
907
key -= 256
908
notNull = True
909
colType = INFORMIX_TYPES.get(key, colType)
910
if notNull:
911
colType = "%s NOT NULL" % colType
912
913
column = safeSQLIdentificatorNaming(column)
914
columns[column] = colType
915
else:
916
column = safeSQLIdentificatorNaming(column)
917
columns[column] = None
918
919
if columns:
920
if conf.db in kb.data.cachedColumns:
921
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns
922
else:
923
table[safeSQLIdentificatorNaming(tbl, True)] = columns
924
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
925
926
if not kb.data.cachedColumns:
927
warnMsg = "unable to retrieve column names for "
928
warnMsg += ("table '%s' " % unsafeSQLIdentificatorNaming(unArrayizeValue(tblList))) if len(tblList) == 1 else "any table "
929
if METADB_SUFFIX not in conf.db:
930
warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
931
logger.warning(warnMsg)
932
933
if bruteForce is None:
934
return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True)
935
936
return kb.data.cachedColumns
937
938
@stackedmethod
939
def getSchema(self):
940
infoMsg = "enumerating database management system schema"
941
logger.info(infoMsg)
942
943
try:
944
pushValue(conf.db)
945
pushValue(conf.tbl)
946
pushValue(conf.col)
947
948
kb.data.cachedTables = {}
949
kb.data.cachedColumns = {}
950
951
self.getTables()
952
953
infoMsg = "fetched tables: "
954
infoMsg += ", ".join(["%s" % ", ".join("'%s%s%s'" % (unsafeSQLIdentificatorNaming(db), ".." if Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) else '.', unsafeSQLIdentificatorNaming(_)) if db else "'%s'" % unsafeSQLIdentificatorNaming(_) for _ in tbl) for db, tbl in kb.data.cachedTables.items()])
955
logger.info(infoMsg)
956
957
for db, tables in kb.data.cachedTables.items():
958
for tbl in tables:
959
conf.db = db
960
conf.tbl = tbl
961
962
self.getColumns()
963
finally:
964
conf.col = popValue()
965
conf.tbl = popValue()
966
conf.db = popValue()
967
968
return kb.data.cachedColumns
969
970
def _tableGetCount(self, db, table):
971
if not db or not table:
972
return None
973
974
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
975
db = db.upper()
976
table = table.upper()
977
978
if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI, DBMS.EXTREMEDB):
979
query = "SELECT %s FROM %s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(table, True))
980
else:
981
query = "SELECT %s FROM %s.%s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(table, True))
982
983
query = agent.whereQuery(query)
984
count = inject.getValue(query, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
985
986
if isNumPosStrValue(count):
987
if safeSQLIdentificatorNaming(db) not in kb.data.cachedCounts:
988
kb.data.cachedCounts[safeSQLIdentificatorNaming(db)] = {}
989
990
if int(count) in kb.data.cachedCounts[safeSQLIdentificatorNaming(db)]:
991
kb.data.cachedCounts[safeSQLIdentificatorNaming(db)][int(count)].append(safeSQLIdentificatorNaming(table, True))
992
else:
993
kb.data.cachedCounts[safeSQLIdentificatorNaming(db)][int(count)] = [safeSQLIdentificatorNaming(table, True)]
994
995
def getCount(self):
996
if not conf.tbl:
997
warnMsg = "missing table parameter, sqlmap will retrieve "
998
warnMsg += "the number of entries for all database "
999
warnMsg += "management system databases' tables"
1000
logger.warning(warnMsg)
1001
1002
elif "." in conf.tbl:
1003
if not conf.db:
1004
conf.db, conf.tbl = conf.tbl.split('.', 1)
1005
1006
if conf.tbl is not None and conf.db is None and Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI, DBMS.EXTREMEDB):
1007
warnMsg = "missing database parameter. sqlmap is going to "
1008
warnMsg += "use the current database to retrieve the "
1009
warnMsg += "number of entries for table '%s'" % unsafeSQLIdentificatorNaming(conf.tbl)
1010
logger.warning(warnMsg)
1011
1012
conf.db = self.getCurrentDb()
1013
1014
self.forceDbmsEnum()
1015
1016
if conf.tbl:
1017
for table in conf.tbl.split(','):
1018
self._tableGetCount(conf.db, table)
1019
else:
1020
self.getTables()
1021
1022
for db, tables in kb.data.cachedTables.items():
1023
for table in tables:
1024
self._tableGetCount(db, table)
1025
1026
return kb.data.cachedCounts
1027
1028
def getStatements(self):
1029
infoMsg = "fetching SQL statements"
1030
logger.info(infoMsg)
1031
1032
rootQuery = queries[Backend.getIdentifiedDbms()].statements
1033
1034
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
1035
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
1036
query = rootQuery.inband.query2
1037
else:
1038
query = rootQuery.inband.query
1039
1040
while True:
1041
values = inject.getValue(query, blind=False, time=False)
1042
1043
if not isNoneValue(values):
1044
kb.data.cachedStatements = []
1045
for value in arrayizeValue(values):
1046
value = (unArrayizeValue(value) or "").strip()
1047
if not isNoneValue(value):
1048
kb.data.cachedStatements.append(value.strip())
1049
1050
elif Backend.isDbms(DBMS.PGSQL) and "current_query" not in query:
1051
query = query.replace("query", "current_query")
1052
continue
1053
1054
break
1055
1056
if not kb.data.cachedStatements and isInferenceAvailable() and not conf.direct:
1057
infoMsg = "fetching number of statements"
1058
logger.info(infoMsg)
1059
1060
query = rootQuery.blind.count
1061
1062
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
1063
query = re.sub("INFORMATION_SCHEMA", "DATA_DICTIONARY", query, flags=re.I)
1064
1065
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
1066
1067
if count == 0:
1068
return kb.data.cachedStatements
1069
elif not isNumPosStrValue(count):
1070
errMsg = "unable to retrieve the number of statements"
1071
raise SqlmapNoneDataException(errMsg)
1072
1073
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
1074
indexRange = getLimitRange(count, plusOne=plusOne)
1075
1076
for index in indexRange:
1077
value = None
1078
1079
if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): # case with multiple processes
1080
query = rootQuery.blind.query3 % index
1081
identifier = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT))
1082
1083
if not isNoneValue(identifier):
1084
query = rootQuery.blind.query2 % identifier
1085
value = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT))
1086
1087
if isNoneValue(value):
1088
query = rootQuery.blind.query % index
1089
1090
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
1091
query = re.sub("INFORMATION_SCHEMA", "DATA_DICTIONARY", query, flags=re.I)
1092
1093
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
1094
1095
if not isNoneValue(value):
1096
kb.data.cachedStatements.append(value)
1097
1098
if not kb.data.cachedStatements:
1099
errMsg = "unable to retrieve the statements"
1100
logger.error(errMsg)
1101
else:
1102
kb.data.cachedStatements = [_.replace(REFLECTED_VALUE_MARKER, "<payload>") for _ in kb.data.cachedStatements]
1103
1104
return kb.data.cachedStatements
1105
1106