Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/plugins/generic/databases.py
2989 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 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):
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):
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):
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):
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):
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.getIdentifiedDbms() in (DBMS.MONETDB, DBMS.CLICKHOUSE):
842
query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index))
843
field = None
844
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE):
845
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
846
query += condQuery
847
field = None
848
elif Backend.isDbms(DBMS.MSSQL):
849
query = rootQuery.blind.query.replace("'%s'", "'%s'" % unsafeSQLIdentificatorNaming(tbl).split(".")[-1]).replace("%s", conf.db).replace("%d", str(index))
850
query += condQuery.replace("[DB]", conf.db)
851
field = condition.replace("[DB]", conf.db)
852
elif Backend.isDbms(DBMS.FIREBIRD):
853
query = rootQuery.blind.query % unsafeSQLIdentificatorNaming(tbl)
854
query += condQuery
855
field = None
856
elif Backend.isDbms(DBMS.INFORMIX):
857
query = rootQuery.blind.query % (index, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))
858
query += condQuery
859
field = condition
860
861
query = agent.limitQuery(index, query, field, field)
862
column = unArrayizeValue(inject.getValue(query, union=False, error=False))
863
864
if not isNoneValue(column):
865
if conf.getComments:
866
_ = queries[Backend.getIdentifiedDbms()].column_comment
867
if hasattr(_, "query"):
868
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
869
query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper()))
870
else:
871
query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column))
872
873
comment = unArrayizeValue(inject.getValue(query, union=False, error=False))
874
if not isNoneValue(comment):
875
infoMsg = "retrieved comment '%s' for column '%s'" % (comment, column)
876
logger.info(infoMsg)
877
else:
878
warnMsg = "on %s it is not " % Backend.getIdentifiedDbms()
879
warnMsg += "possible to get column comments"
880
singleTimeWarnMessage(warnMsg)
881
882
if not onlyColNames:
883
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):
884
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db))
885
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL):
886
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper()))
887
elif Backend.isDbms(DBMS.MSSQL):
888
query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1])
889
elif Backend.isDbms(DBMS.FIREBIRD):
890
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column)
891
elif Backend.isDbms(DBMS.INFORMIX):
892
query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl), column)
893
elif Backend.isDbms(DBMS.MONETDB):
894
query = rootQuery.blind.query2 % (column, unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
895
896
colType = unArrayizeValue(inject.getValue(query, union=False, error=False))
897
key = int(colType) if hasattr(colType, "isdigit") and colType.isdigit() else colType
898
899
if Backend.isDbms(DBMS.FIREBIRD):
900
colType = FIREBIRD_TYPES.get(key, colType)
901
elif Backend.isDbms(DBMS.INFORMIX):
902
notNull = False
903
if isinstance(key, int) and key > 255:
904
key -= 256
905
notNull = True
906
colType = INFORMIX_TYPES.get(key, colType)
907
if notNull:
908
colType = "%s NOT NULL" % colType
909
910
column = safeSQLIdentificatorNaming(column)
911
columns[column] = colType
912
else:
913
column = safeSQLIdentificatorNaming(column)
914
columns[column] = None
915
916
if columns:
917
if conf.db in kb.data.cachedColumns:
918
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns
919
else:
920
table[safeSQLIdentificatorNaming(tbl, True)] = columns
921
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
922
923
if not kb.data.cachedColumns:
924
warnMsg = "unable to retrieve column names for "
925
warnMsg += ("table '%s' " % unsafeSQLIdentificatorNaming(unArrayizeValue(tblList))) if len(tblList) == 1 else "any table "
926
if METADB_SUFFIX not in conf.db:
927
warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
928
logger.warning(warnMsg)
929
930
if bruteForce is None:
931
return self.getColumns(onlyColNames=onlyColNames, colTuple=colTuple, bruteForce=True)
932
933
return kb.data.cachedColumns
934
935
@stackedmethod
936
def getSchema(self):
937
infoMsg = "enumerating database management system schema"
938
logger.info(infoMsg)
939
940
try:
941
pushValue(conf.db)
942
pushValue(conf.tbl)
943
pushValue(conf.col)
944
945
kb.data.cachedTables = {}
946
kb.data.cachedColumns = {}
947
948
self.getTables()
949
950
infoMsg = "fetched tables: "
951
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()])
952
logger.info(infoMsg)
953
954
for db, tables in kb.data.cachedTables.items():
955
for tbl in tables:
956
conf.db = db
957
conf.tbl = tbl
958
959
self.getColumns()
960
finally:
961
conf.col = popValue()
962
conf.tbl = popValue()
963
conf.db = popValue()
964
965
return kb.data.cachedColumns
966
967
def _tableGetCount(self, db, table):
968
if not db or not table:
969
return None
970
971
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
972
db = db.upper()
973
table = table.upper()
974
975
if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI, DBMS.EXTREMEDB):
976
query = "SELECT %s FROM %s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(table, True))
977
else:
978
query = "SELECT %s FROM %s.%s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(table, True))
979
980
query = agent.whereQuery(query)
981
count = inject.getValue(query, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
982
983
if isNumPosStrValue(count):
984
if safeSQLIdentificatorNaming(db) not in kb.data.cachedCounts:
985
kb.data.cachedCounts[safeSQLIdentificatorNaming(db)] = {}
986
987
if int(count) in kb.data.cachedCounts[safeSQLIdentificatorNaming(db)]:
988
kb.data.cachedCounts[safeSQLIdentificatorNaming(db)][int(count)].append(safeSQLIdentificatorNaming(table, True))
989
else:
990
kb.data.cachedCounts[safeSQLIdentificatorNaming(db)][int(count)] = [safeSQLIdentificatorNaming(table, True)]
991
992
def getCount(self):
993
if not conf.tbl:
994
warnMsg = "missing table parameter, sqlmap will retrieve "
995
warnMsg += "the number of entries for all database "
996
warnMsg += "management system databases' tables"
997
logger.warning(warnMsg)
998
999
elif "." in conf.tbl:
1000
if not conf.db:
1001
conf.db, conf.tbl = conf.tbl.split('.', 1)
1002
1003
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):
1004
warnMsg = "missing database parameter. sqlmap is going to "
1005
warnMsg += "use the current database to retrieve the "
1006
warnMsg += "number of entries for table '%s'" % unsafeSQLIdentificatorNaming(conf.tbl)
1007
logger.warning(warnMsg)
1008
1009
conf.db = self.getCurrentDb()
1010
1011
self.forceDbmsEnum()
1012
1013
if conf.tbl:
1014
for table in conf.tbl.split(','):
1015
self._tableGetCount(conf.db, table)
1016
else:
1017
self.getTables()
1018
1019
for db, tables in kb.data.cachedTables.items():
1020
for table in tables:
1021
self._tableGetCount(db, table)
1022
1023
return kb.data.cachedCounts
1024
1025
def getStatements(self):
1026
infoMsg = "fetching SQL statements"
1027
logger.info(infoMsg)
1028
1029
rootQuery = queries[Backend.getIdentifiedDbms()].statements
1030
1031
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
1032
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
1033
query = rootQuery.inband.query2
1034
else:
1035
query = rootQuery.inband.query
1036
1037
while True:
1038
values = inject.getValue(query, blind=False, time=False)
1039
1040
if not isNoneValue(values):
1041
kb.data.cachedStatements = []
1042
for value in arrayizeValue(values):
1043
value = (unArrayizeValue(value) or "").strip()
1044
if not isNoneValue(value):
1045
kb.data.cachedStatements.append(value.strip())
1046
1047
elif Backend.isDbms(DBMS.PGSQL) and "current_query" not in query:
1048
query = query.replace("query", "current_query")
1049
continue
1050
1051
break
1052
1053
if not kb.data.cachedStatements and isInferenceAvailable() and not conf.direct:
1054
infoMsg = "fetching number of statements"
1055
logger.info(infoMsg)
1056
1057
query = rootQuery.blind.count
1058
1059
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
1060
query = re.sub("INFORMATION_SCHEMA", "DATA_DICTIONARY", query, flags=re.I)
1061
1062
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
1063
1064
if count == 0:
1065
return kb.data.cachedStatements
1066
elif not isNumPosStrValue(count):
1067
errMsg = "unable to retrieve the number of statements"
1068
raise SqlmapNoneDataException(errMsg)
1069
1070
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
1071
indexRange = getLimitRange(count, plusOne=plusOne)
1072
1073
for index in indexRange:
1074
value = None
1075
1076
if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): # case with multiple processes
1077
query = rootQuery.blind.query3 % index
1078
identifier = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT))
1079
1080
if not isNoneValue(identifier):
1081
query = rootQuery.blind.query2 % identifier
1082
value = unArrayizeValue(inject.getValue(query, union=False, error=False, expected=EXPECTED.INT))
1083
1084
if isNoneValue(value):
1085
query = rootQuery.blind.query % index
1086
1087
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
1088
query = re.sub("INFORMATION_SCHEMA", "DATA_DICTIONARY", query, flags=re.I)
1089
1090
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
1091
1092
if not isNoneValue(value):
1093
kb.data.cachedStatements.append(value)
1094
1095
if not kb.data.cachedStatements:
1096
errMsg = "unable to retrieve the statements"
1097
logger.error(errMsg)
1098
else:
1099
kb.data.cachedStatements = [_.replace(REFLECTED_VALUE_MARKER, "<payload>") for _ in kb.data.cachedStatements]
1100
1101
return kb.data.cachedStatements
1102
1103