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