Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/core/dump.py
3554 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 hashlib
9
import os
10
import re
11
import shutil
12
import tempfile
13
import threading
14
15
from lib.core.common import Backend
16
from lib.core.common import checkFile
17
from lib.core.common import dataToDumpFile
18
from lib.core.common import dataToStdout
19
from lib.core.common import filterNone
20
from lib.core.common import getSafeExString
21
from lib.core.common import isListLike
22
from lib.core.common import isNoneValue
23
from lib.core.common import normalizeUnicode
24
from lib.core.common import openFile
25
from lib.core.common import prioritySortColumns
26
from lib.core.common import randomInt
27
from lib.core.common import safeCSValue
28
from lib.core.common import unArrayizeValue
29
from lib.core.common import unsafeSQLIdentificatorNaming
30
from lib.core.compat import xrange
31
from lib.core.convert import getBytes
32
from lib.core.convert import getConsoleLength
33
from lib.core.convert import getText
34
from lib.core.convert import getUnicode
35
from lib.core.convert import htmlEscape
36
from lib.core.data import conf
37
from lib.core.data import kb
38
from lib.core.data import logger
39
from lib.core.dicts import DUMP_REPLACEMENTS
40
from lib.core.enums import CONTENT_STATUS
41
from lib.core.enums import CONTENT_TYPE
42
from lib.core.enums import DBMS
43
from lib.core.enums import DUMP_FORMAT
44
from lib.core.exception import SqlmapGenericException
45
from lib.core.exception import SqlmapSystemException
46
from lib.core.exception import SqlmapValueException
47
from lib.core.replication import Replication
48
from lib.core.settings import CHECK_SQLITE_TYPE_THRESHOLD
49
from lib.core.settings import DUMP_FILE_BUFFER_SIZE
50
from lib.core.settings import HTML_DUMP_CSS_STYLE
51
from lib.core.settings import IS_WIN
52
from lib.core.settings import METADB_SUFFIX
53
from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE
54
from lib.core.settings import TRIM_STDOUT_DUMP_SIZE
55
from lib.core.settings import UNICODE_ENCODING
56
from lib.core.settings import UNSAFE_DUMP_FILEPATH_REPLACEMENT
57
from lib.core.settings import VERSION_STRING
58
from lib.core.settings import WINDOWS_RESERVED_NAMES
59
from lib.utils.safe2bin import safechardecode
60
from thirdparty import six
61
from thirdparty.magic import magic
62
63
class Dump(object):
64
"""
65
This class defines methods used to parse and output the results
66
of SQL injection actions
67
"""
68
69
def __init__(self):
70
self._outputFile = None
71
self._outputFP = None
72
self._lock = threading.Lock()
73
74
def _write(self, data, newline=True, console=True, content_type=None):
75
text = "%s%s" % (data, "\n" if newline else " ")
76
77
if conf.api:
78
dataToStdout(data, contentType=content_type, status=CONTENT_STATUS.COMPLETE)
79
80
elif console:
81
dataToStdout(text)
82
83
if self._outputFP:
84
multiThreadMode = kb.multiThreadMode
85
if multiThreadMode:
86
self._lock.acquire()
87
88
try:
89
self._outputFP.write(text)
90
except IOError as ex:
91
errMsg = "error occurred while writing to log file ('%s')" % getSafeExString(ex)
92
raise SqlmapGenericException(errMsg)
93
94
if multiThreadMode:
95
self._lock.release()
96
97
kb.dataOutputFlag = True
98
99
def flush(self):
100
if self._outputFP:
101
try:
102
self._outputFP.flush()
103
except IOError:
104
pass
105
106
def setOutputFile(self):
107
if conf.noLogging:
108
self._outputFP = None
109
return
110
111
self._outputFile = os.path.join(conf.outputPath, "log")
112
try:
113
self._outputFP = openFile(self._outputFile, 'a' if not conf.flushSession else 'w')
114
except IOError as ex:
115
errMsg = "error occurred while opening log file ('%s')" % getSafeExString(ex)
116
raise SqlmapGenericException(errMsg)
117
118
def singleString(self, data, content_type=None):
119
self._write(data, content_type=content_type)
120
121
def string(self, header, data, content_type=None, sort=True):
122
if conf.api:
123
self._write(data, content_type=content_type)
124
125
if isListLike(data) and len(data) == 1:
126
data = unArrayizeValue(data)
127
128
if isListLike(data):
129
self.lister(header, data, content_type, sort)
130
elif data is not None:
131
_ = getUnicode(data)
132
133
if _.endswith("\r\n"):
134
_ = _[:-2]
135
136
elif _.endswith("\n"):
137
_ = _[:-1]
138
139
if _.strip(' '):
140
_ = _.strip(' ')
141
142
if "\n" in _:
143
self._write("%s:\n---\n%s\n---" % (header, _))
144
else:
145
self._write("%s: %s" % (header, ("'%s'" % _) if isinstance(data, six.string_types) else _))
146
147
def lister(self, header, elements, content_type=None, sort=True):
148
if elements and sort:
149
try:
150
elements = set(elements)
151
elements = list(elements)
152
elements.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
153
except:
154
pass
155
156
if conf.api:
157
self._write(elements, content_type=content_type)
158
159
if elements:
160
self._write("%s [%d]:" % (header, len(elements)))
161
162
for element in elements:
163
if isinstance(element, six.string_types):
164
self._write("[*] %s" % element)
165
elif isListLike(element):
166
self._write("[*] " + ", ".join(getUnicode(e) for e in element))
167
168
if elements:
169
self._write("")
170
171
def banner(self, data):
172
self.string("banner", data, content_type=CONTENT_TYPE.BANNER)
173
174
def currentUser(self, data):
175
self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER)
176
177
def currentDb(self, data):
178
if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE, DBMS.SNOWFLAKE):
179
self.string("current database (equivalent to schema on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
180
elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB, DBMS.VIRTUOSO):
181
self.string("current database (equivalent to owner on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
182
else:
183
self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB)
184
185
def hostname(self, data):
186
self.string("hostname", data, content_type=CONTENT_TYPE.HOSTNAME)
187
188
def dba(self, data):
189
self.string("current user is DBA", data, content_type=CONTENT_TYPE.IS_DBA)
190
191
def users(self, users):
192
self.lister("database management system users", users, content_type=CONTENT_TYPE.USERS)
193
194
def statements(self, statements):
195
self.lister("SQL statements", statements, content_type=CONTENT_TYPE.STATEMENTS)
196
197
def userSettings(self, header, userSettings, subHeader, content_type=None):
198
self._areAdmins = set()
199
200
if isinstance(userSettings, (tuple, list, set)):
201
self._areAdmins = userSettings[1]
202
userSettings = userSettings[0]
203
204
users = [_ for _ in userSettings.keys() if _ is not None]
205
users.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
206
207
if conf.api:
208
self._write(userSettings, content_type=content_type)
209
210
if userSettings:
211
self._write("%s:" % header)
212
213
for user in users:
214
settings = filterNone(userSettings[user])
215
216
if isNoneValue(settings):
217
stringSettings = ""
218
else:
219
stringSettings = " [%d]:" % len(settings)
220
221
if user in self._areAdmins:
222
self._write("[*] %s (administrator)%s" % (user, stringSettings))
223
else:
224
self._write("[*] %s%s" % (user, stringSettings))
225
226
if settings:
227
settings.sort()
228
229
for setting in settings:
230
self._write(" %s: %s" % (subHeader, setting))
231
232
if userSettings:
233
self.singleString("")
234
235
def dbs(self, dbs):
236
self.lister("available databases", dbs, content_type=CONTENT_TYPE.DBS)
237
238
def dbTables(self, dbTables):
239
if isinstance(dbTables, dict) and len(dbTables) > 0:
240
if conf.api:
241
self._write(dbTables, content_type=CONTENT_TYPE.TABLES)
242
243
maxlength = 0
244
245
for tables in dbTables.values():
246
for table in tables:
247
if table and isListLike(table):
248
table = table[0]
249
250
maxlength = max(maxlength, getConsoleLength(unsafeSQLIdentificatorNaming(getUnicode(table))))
251
252
lines = "-" * (int(maxlength) + 2)
253
254
for db, tables in dbTables.items():
255
tables = sorted(filter(None, tables))
256
257
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>")
258
259
if len(tables) == 1:
260
self._write("[1 table]")
261
else:
262
self._write("[%d tables]" % len(tables))
263
264
self._write("+%s+" % lines)
265
266
for table in tables:
267
if table and isListLike(table):
268
table = table[0]
269
270
table = unsafeSQLIdentificatorNaming(table)
271
blank = " " * (maxlength - getConsoleLength(getUnicode(table)))
272
self._write("| %s%s |" % (table, blank))
273
274
self._write("+%s+\n" % lines)
275
elif dbTables is None or len(dbTables) == 0:
276
self.singleString("No tables found", content_type=CONTENT_TYPE.TABLES)
277
else:
278
self.string("tables", dbTables, content_type=CONTENT_TYPE.TABLES)
279
280
def dbTableColumns(self, tableColumns, content_type=None):
281
if isinstance(tableColumns, dict) and len(tableColumns) > 0:
282
if conf.api:
283
self._write(tableColumns, content_type=content_type)
284
285
for db, tables in tableColumns.items():
286
if not db:
287
db = "All"
288
289
for table, columns in tables.items():
290
maxlength1 = 0
291
maxlength2 = 0
292
293
colType = None
294
295
colList = list(columns.keys())
296
colList.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
297
298
for column in colList:
299
colType = columns[column]
300
301
column = unsafeSQLIdentificatorNaming(column)
302
maxlength1 = max(maxlength1, len(column or ""))
303
maxlength2 = max(maxlength2, len(colType or ""))
304
305
maxlength1 = max(maxlength1, len("COLUMN"))
306
lines1 = "-" * (maxlength1 + 2)
307
308
if colType is not None:
309
maxlength2 = max(maxlength2, len("TYPE"))
310
lines2 = "-" * (maxlength2 + 2)
311
312
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>", unsafeSQLIdentificatorNaming(table)))
313
314
if len(columns) == 1:
315
self._write("[1 column]")
316
else:
317
self._write("[%d columns]" % len(columns))
318
319
if colType is not None:
320
self._write("+%s+%s+" % (lines1, lines2))
321
else:
322
self._write("+%s+" % lines1)
323
324
blank1 = " " * (maxlength1 - len("COLUMN"))
325
326
if colType is not None:
327
blank2 = " " * (maxlength2 - len("TYPE"))
328
329
if colType is not None:
330
self._write("| Column%s | Type%s |" % (blank1, blank2))
331
self._write("+%s+%s+" % (lines1, lines2))
332
else:
333
self._write("| Column%s |" % blank1)
334
self._write("+%s+" % lines1)
335
336
for column in colList:
337
colType = columns[column]
338
339
column = unsafeSQLIdentificatorNaming(column)
340
blank1 = " " * (maxlength1 - len(column))
341
342
if colType is not None:
343
blank2 = " " * (maxlength2 - len(colType))
344
self._write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
345
else:
346
self._write("| %s%s |" % (column, blank1))
347
348
if colType is not None:
349
self._write("+%s+%s+\n" % (lines1, lines2))
350
else:
351
self._write("+%s+\n" % lines1)
352
353
def dbTablesCount(self, dbTables):
354
if isinstance(dbTables, dict) and len(dbTables) > 0:
355
if conf.api:
356
self._write(dbTables, content_type=CONTENT_TYPE.COUNT)
357
358
maxlength1 = len("Table")
359
maxlength2 = len("Entries")
360
361
for ctables in dbTables.values():
362
for tables in ctables.values():
363
for table in tables:
364
maxlength1 = max(maxlength1, getConsoleLength(getUnicode(table)))
365
366
for db, counts in dbTables.items():
367
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>")
368
369
lines1 = "-" * (maxlength1 + 2)
370
blank1 = " " * (maxlength1 - len("Table"))
371
lines2 = "-" * (maxlength2 + 2)
372
blank2 = " " * (maxlength2 - len("Entries"))
373
374
self._write("+%s+%s+" % (lines1, lines2))
375
self._write("| Table%s | Entries%s |" % (blank1, blank2))
376
self._write("+%s+%s+" % (lines1, lines2))
377
378
sortedCounts = list(counts.keys())
379
sortedCounts.sort(reverse=True)
380
381
for count in sortedCounts:
382
tables = counts[count]
383
384
if count is None:
385
count = "Unknown"
386
387
tables.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
388
389
for table in tables:
390
blank1 = " " * (maxlength1 - getConsoleLength(getUnicode(table)))
391
blank2 = " " * (maxlength2 - len(str(count)))
392
self._write("| %s%s | %d%s |" % (table, blank1, count, blank2))
393
394
self._write("+%s+%s+\n" % (lines1, lines2))
395
else:
396
logger.error("unable to retrieve the number of entries for any table")
397
398
def dbTableValues(self, tableValues):
399
replication = None
400
rtable = None
401
dumpFP = None
402
appendToFile = False
403
warnFile = False
404
405
if tableValues is None:
406
return
407
408
db = tableValues["__infos__"]["db"]
409
if not db:
410
db = "All"
411
table = tableValues["__infos__"]["table"]
412
413
if conf.api:
414
self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE)
415
416
try:
417
dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db))
418
except UnicodeError:
419
try:
420
dumpDbPath = os.path.join(conf.dumpPath, normalizeUnicode(unsafeSQLIdentificatorNaming(db)))
421
except (UnicodeError, OSError):
422
tempDir = tempfile.mkdtemp(prefix="sqlmapdb")
423
warnMsg = "currently unable to use regular dump directory. "
424
warnMsg += "Using temporary directory '%s' instead" % tempDir
425
logger.warning(warnMsg)
426
427
dumpDbPath = tempDir
428
429
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
430
replication = Replication(os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db)))
431
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
432
if not os.path.isdir(dumpDbPath):
433
try:
434
os.makedirs(dumpDbPath)
435
except:
436
warnFile = True
437
438
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(db))
439
dumpDbPath = os.path.join(conf.dumpPath, "%s-%s" % (_, hashlib.md5(getBytes(db)).hexdigest()[:8]))
440
441
if not os.path.isdir(dumpDbPath):
442
try:
443
os.makedirs(dumpDbPath)
444
except Exception as ex:
445
tempDir = tempfile.mkdtemp(prefix="sqlmapdb")
446
warnMsg = "unable to create dump directory "
447
warnMsg += "'%s' (%s). " % (dumpDbPath, getSafeExString(ex))
448
warnMsg += "Using temporary directory '%s' instead" % tempDir
449
logger.warning(warnMsg)
450
451
dumpDbPath = tempDir
452
453
dumpFileName = conf.dumpFile or os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())))
454
if not checkFile(dumpFileName, False):
455
try:
456
openFile(dumpFileName, "w+").close()
457
except SqlmapSystemException:
458
raise
459
except:
460
warnFile = True
461
462
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(table)))
463
if len(_) < len(table) or IS_WIN and table.upper() in WINDOWS_RESERVED_NAMES:
464
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(table))
465
dumpFileName = os.path.join(dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(getBytes(table)).hexdigest()[:8], conf.dumpFormat.lower()))
466
else:
467
dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower()))
468
else:
469
appendToFile = any((conf.limitStart, conf.limitStop))
470
471
if not appendToFile:
472
count = 1
473
while True:
474
candidate = "%s.%d" % (dumpFileName, count)
475
if not checkFile(candidate, False):
476
try:
477
shutil.copyfile(dumpFileName, candidate)
478
except IOError:
479
pass
480
break
481
else:
482
count += 1
483
484
dumpFP = openFile(dumpFileName, 'w' if not appendToFile else 'a', buffering=DUMP_FILE_BUFFER_SIZE)
485
486
count = int(tableValues["__infos__"]["count"])
487
if count > TRIM_STDOUT_DUMP_SIZE:
488
warnMsg = "console output will be trimmed to "
489
warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE
490
warnMsg += "large table size"
491
logger.warning(warnMsg)
492
493
separator = str()
494
field = 1
495
fields = len(tableValues) - 1
496
497
columns = prioritySortColumns(list(tableValues.keys()))
498
499
if conf.col:
500
cols = conf.col.split(',')
501
columns = sorted(columns, key=lambda _: cols.index(_) if _ in cols else 0)
502
503
for column in columns:
504
if column != "__infos__":
505
info = tableValues[column]
506
lines = "-" * (int(info["length"]) + 2)
507
separator += "+%s" % lines
508
509
separator += "+"
510
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db and METADB_SUFFIX not in db else "<current>", unsafeSQLIdentificatorNaming(table)))
511
512
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
513
cols = []
514
515
for column in columns:
516
if column != "__infos__":
517
colType = Replication.INTEGER
518
519
for i in xrange(min(CHECK_SQLITE_TYPE_THRESHOLD, len(tableValues[column]['values']))):
520
value = tableValues[column]['values'][i]
521
try:
522
if not value or value == " ": # NULL
523
continue
524
525
int(value)
526
except ValueError:
527
colType = None
528
break
529
530
if colType is None:
531
colType = Replication.REAL
532
533
for i in xrange(min(CHECK_SQLITE_TYPE_THRESHOLD, len(tableValues[column]['values']))):
534
value = tableValues[column]['values'][i]
535
try:
536
if not value or value == " ": # NULL
537
continue
538
539
float(value)
540
except ValueError:
541
colType = None
542
break
543
544
cols.append((unsafeSQLIdentificatorNaming(column), colType if colType else Replication.TEXT))
545
546
rtable = replication.createTable(table, cols)
547
elif conf.dumpFormat == DUMP_FORMAT.HTML:
548
dataToDumpFile(dumpFP, "<!DOCTYPE html>\n<html>\n<head>\n")
549
dataToDumpFile(dumpFP, "<meta http-equiv=\"Content-type\" content=\"text/html;charset=%s\">\n" % UNICODE_ENCODING)
550
dataToDumpFile(dumpFP, "<meta name=\"generator\" content=\"%s\" />\n" % VERSION_STRING)
551
dataToDumpFile(dumpFP, "<title>%s</title>\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table)))
552
dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE)
553
dataToDumpFile(dumpFP, "\n</head>\n<body>\n<table>\n<thead>\n<tr>\n")
554
555
if count == 1:
556
self._write("[1 entry]")
557
else:
558
self._write("[%d entries]" % count)
559
560
self._write(separator)
561
562
for column in columns:
563
if column != "__infos__":
564
info = tableValues[column]
565
566
column = unsafeSQLIdentificatorNaming(column)
567
maxlength = int(info["length"])
568
blank = " " * (maxlength - getConsoleLength(column))
569
570
self._write("| %s%s" % (column, blank), newline=False)
571
572
if not appendToFile:
573
if conf.dumpFormat == DUMP_FORMAT.CSV:
574
if field == fields:
575
dataToDumpFile(dumpFP, "%s" % safeCSValue(column))
576
else:
577
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel))
578
elif conf.dumpFormat == DUMP_FORMAT.HTML:
579
dataToDumpFile(dumpFP, "<th onclick=\"sortTable(%d,this)\">%s</th>" % (field - 1, getUnicode(htmlEscape(column).encode("ascii", "xmlcharrefreplace"))))
580
581
field += 1
582
583
if conf.dumpFormat == DUMP_FORMAT.HTML:
584
dataToDumpFile(dumpFP, "\n</tr>\n</thead>\n<tbody>\n")
585
586
self._write("|\n%s" % separator)
587
588
if conf.dumpFormat == DUMP_FORMAT.CSV:
589
dataToDumpFile(dumpFP, "\n" if not appendToFile else "")
590
591
elif conf.dumpFormat == DUMP_FORMAT.SQLITE:
592
rtable.beginTransaction()
593
594
for i in xrange(count):
595
console = (i >= count - TRIM_STDOUT_DUMP_SIZE)
596
field = 1
597
values = []
598
599
if i == 0 and count > TRIM_STDOUT_DUMP_SIZE:
600
self._write(" ...")
601
602
if conf.dumpFormat == DUMP_FORMAT.HTML:
603
dataToDumpFile(dumpFP, "<tr>")
604
605
for column in columns:
606
if column != "__infos__":
607
info = tableValues[column]
608
609
if len(info["values"]) <= i:
610
continue
611
612
if info["values"][i] is None:
613
value = u''
614
else:
615
value = getUnicode(info["values"][i])
616
value = DUMP_REPLACEMENTS.get(value, value)
617
618
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
619
values.append(value)
620
621
maxlength = int(info["length"])
622
blank = " " * (maxlength - getConsoleLength(value))
623
self._write("| %s%s" % (value, blank), newline=False, console=console)
624
625
if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
626
try:
627
mimetype = getText(magic.from_buffer(value, mime=True))
628
if any(mimetype.startswith(_) for _ in ("application", "image")):
629
if not os.path.isdir(dumpDbPath):
630
os.makedirs(dumpDbPath)
631
632
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(column)))
633
filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8)))
634
warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
635
logger.warning(warnMsg)
636
637
with openFile(filepath, "w+b", None) as f:
638
_ = safechardecode(value, True)
639
f.write(_)
640
641
except Exception as ex:
642
logger.debug(getSafeExString(ex))
643
644
if conf.dumpFormat == DUMP_FORMAT.CSV:
645
if field == fields:
646
dataToDumpFile(dumpFP, "%s" % safeCSValue(value))
647
else:
648
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel))
649
elif conf.dumpFormat == DUMP_FORMAT.HTML:
650
dataToDumpFile(dumpFP, "<td>%s</td>" % getUnicode(htmlEscape(value).encode("ascii", "xmlcharrefreplace")))
651
652
field += 1
653
654
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
655
try:
656
rtable.insert(values)
657
except SqlmapValueException:
658
pass
659
elif conf.dumpFormat == DUMP_FORMAT.CSV:
660
dataToDumpFile(dumpFP, "\n")
661
elif conf.dumpFormat == DUMP_FORMAT.HTML:
662
dataToDumpFile(dumpFP, "</tr>\n")
663
664
self._write("|", console=console)
665
666
self._write("%s\n" % separator)
667
668
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
669
rtable.endTransaction()
670
logger.info("table '%s.%s' dumped to SQLITE database '%s'" % (db, table, replication.dbpath))
671
672
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
673
if conf.dumpFormat == DUMP_FORMAT.HTML:
674
dataToDumpFile(dumpFP, "</tbody>\n</table>\n<script>let lc=-1,ld=1;function sortTable(n,h){var t=document.querySelector(\"table\"),r=Array.from(t.tBodies[0].rows);ld=(lc==n?-ld:1);lc=n;r.sort((a,b)=>{var x=a.cells[n].innerText.trim(),y=b.cells[n].innerText.trim(),nx=parseFloat(x),ny=parseFloat(y);return(!isNaN(nx)&&!isNaN(ny)?(nx-ny)*ld:x.localeCompare(y)*ld)});r.forEach(e=>t.tBodies[0].appendChild(e));Array.from(t.tHead.rows[0].cells).forEach(c=>{c.innerText=c.innerText.replace(/[\u2191\u2193]/g,\"\")});h.innerText=h.innerText+ (ld==1?\"\u2191\":\"\u2193\");}</script>\n</body>\n</html>")
675
else:
676
dataToDumpFile(dumpFP, "\n")
677
dumpFP.close()
678
679
msg = "table '%s.%s' dumped to %s file '%s'" % (db, table, conf.dumpFormat, dumpFileName)
680
if not warnFile:
681
logger.info(msg)
682
else:
683
logger.warning(msg)
684
685
def dbColumns(self, dbColumnsDict, colConsider, dbs):
686
if conf.api:
687
self._write(dbColumnsDict, content_type=CONTENT_TYPE.COLUMNS)
688
689
for column in dbColumnsDict.keys():
690
if colConsider == "1":
691
colConsiderStr = "s LIKE '%s' were" % unsafeSQLIdentificatorNaming(column)
692
else:
693
colConsiderStr = " '%s' was" % unsafeSQLIdentificatorNaming(column)
694
695
found = {}
696
for db, tblData in dbs.items():
697
for tbl, colData in tblData.items():
698
for col, dataType in colData.items():
699
if column.lower() in col.lower():
700
if db in found:
701
if tbl in found[db]:
702
found[db][tbl][col] = dataType
703
else:
704
found[db][tbl] = {col: dataType}
705
else:
706
found[db] = {}
707
found[db][tbl] = {col: dataType}
708
709
continue
710
711
if found:
712
msg = "column%s found in the " % colConsiderStr
713
msg += "following databases:"
714
self._write(msg)
715
716
self.dbTableColumns(found)
717
718
def sqlQuery(self, query, queryRes):
719
self.string(query, queryRes, content_type=CONTENT_TYPE.SQL_QUERY)
720
721
def rFile(self, fileData):
722
self.lister("files saved to", fileData, sort=False, content_type=CONTENT_TYPE.FILE_READ)
723
724
def registerValue(self, registerData):
725
self.string("Registry key value data", registerData, content_type=CONTENT_TYPE.REG_READ, sort=False)
726
727
# object to manage how to print the retrieved queries output to
728
# standard output and sessions file
729
dumper = Dump()
730
731