sqlmap/lib/core/dump.py

715 lines
27 KiB
Python
Raw Normal View History

2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2008-10-15 19:38:22 +04:00
"""
2019-01-05 23:38:52 +03:00
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
2008-10-15 19:38:22 +04:00
"""
2013-10-19 22:54:52 +04:00
import cgi
import hashlib
import os
import re
import shutil
2014-12-12 11:58:42 +03:00
import tempfile
2011-12-28 19:59:30 +04:00
import threading
2008-10-15 19:38:22 +04:00
2011-02-21 01:41:42 +03:00
from lib.core.common import Backend
2016-04-04 13:25:07 +03:00
from lib.core.common import checkFile
2008-10-15 19:38:22 +04:00
from lib.core.common import dataToDumpFile
from lib.core.common import dataToStdout
from lib.core.common import getSafeExString
2012-06-14 17:38:53 +04:00
from lib.core.common import isListLike
from lib.core.common import isMultiThreadMode
from lib.core.common import normalizeUnicode
from lib.core.common import openFile
2012-05-04 02:34:18 +04:00
from lib.core.common import prioritySortColumns
from lib.core.common import randomInt
2011-07-03 02:48:56 +04:00
from lib.core.common import safeCSValue
from lib.core.common import unsafeSQLIdentificatorNaming
2019-03-28 18:04:38 +03:00
from lib.core.compat import xrange
2019-05-03 14:20:15 +03:00
from lib.core.convert import getBytes
from lib.core.convert import getConsoleLength
2019-05-27 14:09:13 +03:00
from lib.core.convert import getText
2019-05-06 01:54:21 +03:00
from lib.core.convert import getUnicode
2008-10-15 19:38:22 +04:00
from lib.core.data import conf
2010-09-24 17:19:35 +04:00
from lib.core.data import kb
2008-10-15 19:38:22 +04:00
from lib.core.data import logger
2012-08-21 13:30:01 +04:00
from lib.core.dicts import DUMP_REPLACEMENTS
from lib.core.enums import CONTENT_STATUS
2013-01-30 19:30:34 +04:00
from lib.core.enums import CONTENT_TYPE
2011-02-21 01:41:42 +03:00
from lib.core.enums import DBMS
2012-11-28 13:58:18 +04:00
from lib.core.enums import DUMP_FORMAT
from lib.core.exception import SqlmapGenericException
2014-12-12 11:58:42 +03:00
from lib.core.exception import SqlmapSystemException
2019-06-04 15:44:06 +03:00
from lib.core.exception import SqlmapValueException
2010-09-24 17:19:35 +04:00
from lib.core.replication import Replication
2016-03-10 16:48:05 +03:00
from lib.core.settings import DUMP_FILE_BUFFER_SIZE
from lib.core.settings import HTML_DUMP_CSS_STYLE
2015-01-22 10:52:15 +03:00
from lib.core.settings import IS_WIN
from lib.core.settings import METADB_SUFFIX
2013-01-17 14:37:45 +04:00
from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE
from lib.core.settings import TRIM_STDOUT_DUMP_SIZE
2011-01-30 14:36:03 +03:00
from lib.core.settings import UNICODE_ENCODING
2018-02-06 12:48:47 +03:00
from lib.core.settings import UNSAFE_DUMP_FILEPATH_REPLACEMENT
2018-09-05 00:24:40 +03:00
from lib.core.settings import VERSION_STRING
2015-01-22 10:52:15 +03:00
from lib.core.settings import WINDOWS_RESERVED_NAMES
2019-09-11 15:05:25 +03:00
from lib.utils.safe2bin import safechardecode
2019-03-28 16:12:11 +03:00
from thirdparty import six
from thirdparty.magic import magic
2008-10-15 19:38:22 +04:00
class Dump(object):
2008-10-15 19:38:22 +04:00
"""
This class defines methods used to parse and output the results
of SQL injection actions
"""
def __init__(self):
2012-02-16 18:42:28 +04:00
self._outputFile = None
self._outputFP = None
self._lock = threading.Lock()
def _write(self, data, newline=True, console=True, content_type=None):
2017-04-10 20:21:22 +03:00
if conf.api:
dataToStdout(data, content_type=content_type, status=CONTENT_STATUS.COMPLETE)
return
2012-07-14 13:23:22 +04:00
text = "%s%s" % (data, "\n" if newline else " ")
if console:
dataToStdout(text)
2010-10-15 14:28:06 +04:00
multiThreadMode = isMultiThreadMode()
if multiThreadMode:
2012-02-16 18:42:28 +04:00
self._lock.acquire()
2011-12-28 19:59:30 +04:00
2014-11-06 13:19:05 +03:00
try:
self._outputFP.write(text)
2019-01-22 02:40:48 +03:00
except IOError as ex:
errMsg = "error occurred while writing to log file ('%s')" % getSafeExString(ex)
2014-11-06 13:19:05 +03:00
raise SqlmapGenericException(errMsg)
2011-12-28 19:59:30 +04:00
if multiThreadMode:
2012-02-16 18:42:28 +04:00
self._lock.release()
2008-10-15 19:38:22 +04:00
2011-05-11 00:44:36 +04:00
kb.dataOutputFlag = True
def flush(self):
if self._outputFP:
try:
self._outputFP.flush()
except IOError:
pass
2008-10-15 19:38:22 +04:00
def setOutputFile(self):
self._outputFile = os.path.join(conf.outputPath, "log")
2012-07-03 02:50:23 +04:00
try:
2014-11-26 15:38:21 +03:00
self._outputFP = openFile(self._outputFile, "ab" if not conf.flushSession else "wb")
2019-01-22 02:40:48 +03:00
except IOError as ex:
errMsg = "error occurred while opening log file ('%s')" % getSafeExString(ex)
raise SqlmapGenericException(errMsg)
2010-09-26 18:56:55 +04:00
def getOutputFile(self):
2012-02-16 18:42:28 +04:00
return self._outputFile
2010-09-26 18:56:55 +04:00
def singleString(self, data, content_type=None):
self._write(data, content_type=content_type)
def string(self, header, data, content_type=None, sort=True):
2017-04-10 20:21:22 +03:00
if conf.api:
2013-02-06 21:45:25 +04:00
self._write(data, content_type=content_type)
return
2012-06-14 17:38:53 +04:00
if isListLike(data):
2013-02-06 21:45:25 +04:00
self.lister(header, data, content_type, sort)
2012-07-12 13:47:51 +04:00
elif data is not None:
2012-07-13 12:11:16 +04:00
_ = getUnicode(data)
2008-10-15 19:38:22 +04:00
if _.endswith("\r\n"):
_ = _[:-2]
elif _.endswith("\n"):
2012-07-13 12:11:16 +04:00
_ = _[:-1]
2011-05-23 18:28:05 +04:00
if _.strip(' '):
_ = _.strip(' ')
2013-02-06 21:45:25 +04:00
if "\n" in _:
2012-07-14 13:23:22 +04:00
self._write("%s:\n---\n%s\n---" % (header, _))
2008-10-15 19:38:22 +04:00
else:
self._write("%s: %s" % (header, ("'%s'" % _) if isinstance(data, six.string_types) else _))
2008-10-15 19:38:22 +04:00
else:
2012-07-14 13:23:22 +04:00
self._write("%s:\tNone" % header)
2010-09-24 17:19:35 +04:00
def lister(self, header, elements, content_type=None, sort=True):
if elements and sort:
try:
elements = set(elements)
elements = list(elements)
elements.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
except:
pass
2008-10-15 19:38:22 +04:00
2017-04-10 20:21:22 +03:00
if conf.api:
self._write(elements, content_type=content_type)
return
if elements:
self._write("%s [%d]:" % (header, len(elements)))
2008-10-15 19:38:22 +04:00
for element in elements:
if isinstance(element, six.string_types):
2012-02-16 18:42:28 +04:00
self._write("[*] %s" % element)
2012-06-14 17:38:53 +04:00
elif isListLike(element):
2012-02-16 18:42:28 +04:00
self._write("[*] " + ", ".join(getUnicode(e) for e in element))
2008-10-15 19:38:22 +04:00
if elements:
2012-02-16 18:42:28 +04:00
self._write("")
2013-01-10 16:18:44 +04:00
def banner(self, data):
2013-01-30 19:30:34 +04:00
self.string("banner", data, content_type=CONTENT_TYPE.BANNER)
2013-01-10 16:18:44 +04:00
def currentUser(self, data):
2013-01-30 19:30:34 +04:00
self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER)
2013-01-10 16:18:44 +04:00
def currentDb(self, data):
if Backend.isDbms(DBMS.MAXDB):
2013-01-30 19:30:34 +04:00
self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
2018-10-16 14:26:55 +03:00
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2):
2013-01-30 19:30:34 +04:00
self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
2011-02-21 01:41:42 +03:00
else:
2013-01-30 19:30:34 +04:00
self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB)
2013-01-10 16:18:44 +04:00
def hostname(self, data):
2013-01-30 19:30:34 +04:00
self.string("hostname", data, content_type=CONTENT_TYPE.HOSTNAME)
2013-01-10 16:18:44 +04:00
def dba(self, data):
2013-01-30 19:30:34 +04:00
self.string("current user is DBA", data, content_type=CONTENT_TYPE.IS_DBA)
2013-01-10 16:18:44 +04:00
def users(self, users):
2013-01-30 19:30:34 +04:00
self.lister("database management system users", users, content_type=CONTENT_TYPE.USERS)
2019-05-29 16:52:33 +03:00
def statements(self, statements):
self.lister("SQL statements", statements, content_type=CONTENT_TYPE.STATEMENTS)
def userSettings(self, header, userSettings, subHeader, content_type=None):
2012-02-16 18:42:28 +04:00
self._areAdmins = set()
2008-10-15 19:38:22 +04:00
if isinstance(userSettings, (tuple, list, set)):
2012-02-16 18:42:28 +04:00
self._areAdmins = userSettings[1]
2008-10-15 19:38:22 +04:00
userSettings = userSettings[0]
2019-10-22 15:39:53 +03:00
users = [_ for _ in userSettings.keys() if _ is not None]
users.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
2008-10-15 19:38:22 +04:00
2017-04-10 20:21:22 +03:00
if conf.api:
self._write(userSettings, content_type=content_type)
return
if userSettings:
self._write("%s:" % header)
2008-10-15 19:38:22 +04:00
for user in users:
settings = userSettings[user]
if settings is None:
stringSettings = ""
else:
stringSettings = " [%d]:" % len(settings)
2012-02-16 18:42:28 +04:00
if user in self._areAdmins:
self._write("[*] %s (administrator)%s" % (user, stringSettings))
2008-10-15 19:38:22 +04:00
else:
2012-02-16 18:42:28 +04:00
self._write("[*] %s%s" % (user, stringSettings))
2008-10-15 19:38:22 +04:00
if settings:
settings.sort()
2008-10-15 19:38:22 +04:00
for setting in settings:
2012-02-16 18:42:28 +04:00
self._write(" %s: %s" % (subHeader, setting))
2012-12-17 17:35:32 +04:00
if userSettings:
self.singleString("")
2013-01-10 16:18:44 +04:00
def dbs(self, dbs):
2013-01-30 19:30:34 +04:00
self.lister("available databases", dbs, content_type=CONTENT_TYPE.DBS)
def dbTables(self, dbTables):
if isinstance(dbTables, dict) and len(dbTables) > 0:
2017-04-10 20:21:22 +03:00
if conf.api:
2013-01-30 19:30:34 +04:00
self._write(dbTables, content_type=CONTENT_TYPE.TABLES)
return
2010-09-30 16:35:45 +04:00
maxlength = 0
for tables in dbTables.values():
for table in tables:
2012-06-14 17:38:53 +04:00
if table and isListLike(table):
table = table[0]
2019-10-29 17:07:29 +03:00
maxlength = max(maxlength, getConsoleLength(unsafeSQLIdentificatorNaming(getUnicode(table))))
2010-09-30 16:35:45 +04:00
lines = "-" * (int(maxlength) + 2)
for db, tables in dbTables.items():
tables.sort()
2010-09-30 16:35:45 +04:00
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db else "Current database")
2010-09-30 16:35:45 +04:00
if len(tables) == 1:
2012-02-16 18:42:28 +04:00
self._write("[1 table]")
2010-09-30 16:35:45 +04:00
else:
2012-02-16 18:42:28 +04:00
self._write("[%d tables]" % len(tables))
2010-09-30 16:35:45 +04:00
2012-02-16 18:42:28 +04:00
self._write("+%s+" % lines)
2010-09-30 16:35:45 +04:00
for table in tables:
2012-06-14 17:38:53 +04:00
if table and isListLike(table):
table = table[0]
2013-02-15 17:48:24 +04:00
table = unsafeSQLIdentificatorNaming(table)
2019-10-29 17:07:29 +03:00
blank = " " * (maxlength - getConsoleLength(getUnicode(table)))
2012-02-16 18:42:28 +04:00
self._write("| %s%s |" % (table, blank))
2010-09-30 16:35:45 +04:00
2012-02-16 18:42:28 +04:00
self._write("+%s+\n" % lines)
2012-03-08 19:11:24 +04:00
elif dbTables is None or len(dbTables) == 0:
2013-01-30 19:30:34 +04:00
self.singleString("No tables found", content_type=CONTENT_TYPE.TABLES)
2010-09-30 16:35:45 +04:00
else:
2013-01-30 19:30:34 +04:00
self.string("tables", dbTables, content_type=CONTENT_TYPE.TABLES)
def dbTableColumns(self, tableColumns, content_type=None):
2011-09-19 23:08:08 +04:00
if isinstance(tableColumns, dict) and len(tableColumns) > 0:
2017-04-10 20:21:22 +03:00
if conf.api:
self._write(tableColumns, content_type=content_type)
return
2011-09-19 23:08:08 +04:00
for db, tables in tableColumns.items():
if not db:
db = "All"
2008-10-15 19:38:22 +04:00
2011-09-19 23:08:08 +04:00
for table, columns in tables.items():
maxlength1 = 0
maxlength2 = 0
2008-10-15 19:38:22 +04:00
2011-09-19 23:08:08 +04:00
colType = None
colList = list(columns.keys())
colList.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
2008-10-15 19:38:22 +04:00
2011-09-19 23:08:08 +04:00
for column in colList:
colType = columns[column]
2008-10-15 19:38:22 +04:00
2013-02-15 17:48:24 +04:00
column = unsafeSQLIdentificatorNaming(column)
2011-09-19 23:08:08 +04:00
maxlength1 = max(maxlength1, len(column or ""))
maxlength2 = max(maxlength2, len(colType or ""))
2011-09-19 23:08:08 +04:00
maxlength1 = max(maxlength1, len("COLUMN"))
lines1 = "-" * (maxlength1 + 2)
2011-09-19 23:08:08 +04:00
if colType is not None:
maxlength2 = max(maxlength2, len("TYPE"))
lines2 = "-" * (maxlength2 + 2)
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db else "Current database", unsafeSQLIdentificatorNaming(table)))
2011-09-19 23:08:08 +04:00
if len(columns) == 1:
2012-02-16 18:42:28 +04:00
self._write("[1 column]")
2011-09-19 23:08:08 +04:00
else:
2012-02-16 18:42:28 +04:00
self._write("[%d columns]" % len(columns))
2008-10-15 19:38:22 +04:00
2011-09-19 23:08:08 +04:00
if colType is not None:
2012-02-16 18:42:28 +04:00
self._write("+%s+%s+" % (lines1, lines2))
2011-09-19 23:08:08 +04:00
else:
2012-02-16 18:42:28 +04:00
self._write("+%s+" % lines1)
2011-09-19 23:08:08 +04:00
blank1 = " " * (maxlength1 - len("COLUMN"))
2011-09-19 23:08:08 +04:00
if colType is not None:
blank2 = " " * (maxlength2 - len("TYPE"))
2008-10-15 19:38:22 +04:00
2011-09-19 23:08:08 +04:00
if colType is not None:
2012-02-16 18:42:28 +04:00
self._write("| Column%s | Type%s |" % (blank1, blank2))
self._write("+%s+%s+" % (lines1, lines2))
2011-09-19 23:08:08 +04:00
else:
2012-02-16 18:42:28 +04:00
self._write("| Column%s |" % blank1)
self._write("+%s+" % lines1)
2011-09-19 23:08:08 +04:00
for column in colList:
colType = columns[column]
2013-02-15 17:48:24 +04:00
column = unsafeSQLIdentificatorNaming(column)
2011-09-19 23:08:08 +04:00
blank1 = " " * (maxlength1 - len(column))
if colType is not None:
blank2 = " " * (maxlength2 - len(colType))
2012-02-16 18:42:28 +04:00
self._write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
2011-09-19 23:08:08 +04:00
else:
2012-02-16 18:42:28 +04:00
self._write("| %s%s |" % (column, blank1))
if colType is not None:
2012-02-16 18:42:28 +04:00
self._write("+%s+%s+\n" % (lines1, lines2))
else:
2012-02-16 18:42:28 +04:00
self._write("+%s+\n" % lines1)
def dbTablesCount(self, dbTables):
if isinstance(dbTables, dict) and len(dbTables) > 0:
2017-04-10 20:21:22 +03:00
if conf.api:
2013-01-30 19:30:34 +04:00
self._write(dbTables, content_type=CONTENT_TYPE.COUNT)
return
maxlength1 = len("Table")
maxlength2 = len("Entries")
for ctables in dbTables.values():
for tables in ctables.values():
for table in tables:
2019-10-29 17:07:29 +03:00
maxlength1 = max(maxlength1, getConsoleLength(getUnicode(table)))
for db, counts in dbTables.items():
self._write("Database: %s" % unsafeSQLIdentificatorNaming(db) if db else "Current database")
lines1 = "-" * (maxlength1 + 2)
blank1 = " " * (maxlength1 - len("Table"))
lines2 = "-" * (maxlength2 + 2)
blank2 = " " * (maxlength2 - len("Entries"))
2012-02-16 18:42:28 +04:00
self._write("+%s+%s+" % (lines1, lines2))
self._write("| Table%s | Entries%s |" % (blank1, blank2))
self._write("+%s+%s+" % (lines1, lines2))
sortedCounts = list(counts.keys())
sortedCounts.sort(reverse=True)
for count in sortedCounts:
tables = counts[count]
if count is None:
count = "Unknown"
tables.sort(key=lambda _: _.lower() if hasattr(_, "lower") else _)
for table in tables:
2019-10-29 17:07:29 +03:00
blank1 = " " * (maxlength1 - getConsoleLength(getUnicode(table)))
blank2 = " " * (maxlength2 - len(str(count)))
2012-02-16 18:42:28 +04:00
self._write("| %s%s | %d%s |" % (table, blank1, count, blank2))
2012-02-16 18:42:28 +04:00
self._write("+%s+%s+\n" % (lines1, lines2))
else:
logger.error("unable to retrieve the number of entries for any table")
def dbTableValues(self, tableValues):
2010-09-24 17:34:46 +04:00
replication = None
2011-04-30 17:20:05 +04:00
rtable = None
dumpFP = None
appendToFile = False
warnFile = False
2010-09-24 17:34:46 +04:00
if tableValues is None:
return
2008-10-15 19:38:22 +04:00
db = tableValues["__infos__"]["db"]
if not db:
db = "All"
table = tableValues["__infos__"]["table"]
2017-04-10 20:21:22 +03:00
if conf.api:
2013-01-30 19:30:34 +04:00
self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE)
return
2016-01-13 16:38:59 +03:00
dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db))
2012-11-28 13:58:18 +04:00
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
replication = Replication(os.path.join(conf.dumpPath, "%s.sqlite3" % unsafeSQLIdentificatorNaming(db)))
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
2008-10-15 19:38:22 +04:00
if not os.path.isdir(dumpDbPath):
2014-12-12 11:58:42 +03:00
try:
os.makedirs(dumpDbPath)
2016-01-12 12:24:28 +03:00
except:
warnFile = True
2019-04-18 17:06:19 +03:00
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(db))
dumpDbPath = os.path.join(conf.dumpPath, "%s-%s" % (_, hashlib.md5(getBytes(db)).hexdigest()[:8]))
2016-01-12 12:24:28 +03:00
if not os.path.isdir(dumpDbPath):
try:
os.makedirs(dumpDbPath)
2019-01-22 02:40:48 +03:00
except Exception as ex:
2019-05-09 11:52:33 +03:00
tempDir = tempfile.mkdtemp(prefix="sqlmapdb")
2016-01-12 12:24:28 +03:00
warnMsg = "unable to create dump directory "
warnMsg += "'%s' (%s). " % (dumpDbPath, getSafeExString(ex))
warnMsg += "Using temporary directory '%s' instead" % tempDir
logger.warn(warnMsg)
dumpDbPath = tempDir
2008-10-15 19:38:22 +04:00
2018-02-06 12:48:47 +03:00
dumpFileName = os.path.join(dumpDbPath, re.sub(r'[\\/]', UNSAFE_DUMP_FILEPATH_REPLACEMENT, "%s.%s" % (unsafeSQLIdentificatorNaming(table), conf.dumpFormat.lower())))
2016-04-04 13:25:07 +03:00
if not checkFile(dumpFileName, False):
2016-01-12 12:34:56 +03:00
try:
openFile(dumpFileName, "w+b").close()
except SqlmapSystemException:
raise
except:
warnFile = True
2018-02-06 12:48:47 +03:00
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(table)))
2016-01-12 12:34:56 +03:00
if len(_) < len(table) or IS_WIN and table.upper() in WINDOWS_RESERVED_NAMES:
2019-04-18 17:06:19 +03:00
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, unsafeSQLIdentificatorNaming(table))
dumpFileName = os.path.join(dumpDbPath, "%s-%s.%s" % (_, hashlib.md5(getBytes(table)).hexdigest()[:8], conf.dumpFormat.lower()))
2016-01-12 12:34:56 +03:00
else:
dumpFileName = os.path.join(dumpDbPath, "%s.%s" % (_, conf.dumpFormat.lower()))
2016-06-05 13:25:42 +03:00
else:
appendToFile = any((conf.limitStart, conf.limitStop))
if not appendToFile:
count = 1
while True:
candidate = "%s.%d" % (dumpFileName, count)
if not checkFile(candidate, False):
2016-06-24 14:31:19 +03:00
try:
shutil.copyfile(dumpFileName, candidate)
except IOError:
pass
2019-05-30 23:40:51 +03:00
break
else:
count += 1
2016-03-10 16:48:05 +03:00
dumpFP = openFile(dumpFileName, "wb" if not appendToFile else "ab", buffering=DUMP_FILE_BUFFER_SIZE)
2008-10-15 19:38:22 +04:00
2011-04-30 17:20:05 +04:00
count = int(tableValues["__infos__"]["count"])
separator = str()
field = 1
fields = len(tableValues) - 1
2008-10-15 19:38:22 +04:00
columns = prioritySortColumns(list(tableValues.keys()))
2008-10-15 19:38:22 +04:00
2014-08-22 16:11:23 +04:00
if conf.col:
cols = conf.col.split(',')
columns = sorted(columns, key=lambda _: cols.index(_) if _ in cols else 0)
2008-10-15 19:38:22 +04:00
for column in columns:
if column != "__infos__":
2011-04-30 17:20:05 +04:00
info = tableValues[column]
lines = "-" * (int(info["length"]) + 2)
2008-10-15 19:38:22 +04:00
separator += "+%s" % lines
separator += "+"
self._write("Database: %s\nTable: %s" % (unsafeSQLIdentificatorNaming(db) if db else "Current database", unsafeSQLIdentificatorNaming(table)))
2008-10-15 19:38:22 +04:00
2012-11-28 13:58:18 +04:00
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
2010-09-24 18:34:05 +04:00
cols = []
2010-11-04 15:21:06 +03:00
2010-09-24 18:34:05 +04:00
for column in columns:
if column != "__infos__":
colType = Replication.INTEGER
2010-11-04 15:21:06 +03:00
2010-09-24 18:34:05 +04:00
for value in tableValues[column]['values']:
try:
2012-03-14 17:52:23 +04:00
if not value or value == " ": # NULL
2010-09-24 18:34:05 +04:00
continue
2010-11-04 15:21:06 +03:00
2012-02-22 14:45:10 +04:00
int(value)
2010-09-24 18:34:05 +04:00
except ValueError:
colType = None
break
2010-11-04 15:21:06 +03:00
2010-09-24 18:34:05 +04:00
if colType is None:
colType = Replication.REAL
2010-11-04 15:21:06 +03:00
2010-09-24 18:34:05 +04:00
for value in tableValues[column]['values']:
try:
2012-03-14 17:52:23 +04:00
if not value or value == " ": # NULL
2010-09-24 18:34:05 +04:00
continue
2010-11-04 15:21:06 +03:00
2012-02-22 14:45:10 +04:00
float(value)
2010-09-24 18:34:05 +04:00
except ValueError:
colType = None
break
2010-11-04 15:21:06 +03:00
cols.append((unsafeSQLIdentificatorNaming(column), colType if colType else Replication.TEXT))
2010-11-04 15:21:06 +03:00
2010-09-24 18:34:05 +04:00
rtable = replication.createTable(table, cols)
elif conf.dumpFormat == DUMP_FORMAT.HTML:
2013-10-19 22:54:52 +04:00
dataToDumpFile(dumpFP, "<!DOCTYPE html>\n<html>\n<head>\n")
dataToDumpFile(dumpFP, "<meta http-equiv=\"Content-type\" content=\"text/html;charset=%s\">\n" % UNICODE_ENCODING)
2018-09-05 00:24:40 +03:00
dataToDumpFile(dumpFP, "<meta name=\"generator\" content=\"%s\" />\n" % VERSION_STRING)
2013-10-19 22:54:52 +04:00
dataToDumpFile(dumpFP, "<title>%s</title>\n" % ("%s%s" % ("%s." % db if METADB_SUFFIX not in db else "", table)))
dataToDumpFile(dumpFP, HTML_DUMP_CSS_STYLE)
dataToDumpFile(dumpFP, "\n</head>\n<body>\n<table>\n<thead>\n<tr>\n")
2010-09-24 17:19:35 +04:00
2008-10-15 19:38:22 +04:00
if count == 1:
2012-02-16 18:42:28 +04:00
self._write("[1 entry]")
2008-10-15 19:38:22 +04:00
else:
2012-02-16 18:42:28 +04:00
self._write("[%d entries]" % count)
2008-10-15 19:38:22 +04:00
2012-02-16 18:42:28 +04:00
self._write(separator)
2008-10-15 19:38:22 +04:00
for column in columns:
if column != "__infos__":
2011-04-30 17:20:05 +04:00
info = tableValues[column]
column = unsafeSQLIdentificatorNaming(column)
2008-10-15 19:38:22 +04:00
maxlength = int(info["length"])
blank = " " * (maxlength - getConsoleLength(column))
2012-07-14 13:23:22 +04:00
self._write("| %s%s" % (column, blank), newline=False)
2008-10-15 19:38:22 +04:00
if not appendToFile:
if conf.dumpFormat == DUMP_FORMAT.CSV:
if field == fields:
dataToDumpFile(dumpFP, "%s" % safeCSValue(column))
else:
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel))
elif conf.dumpFormat == DUMP_FORMAT.HTML:
2019-05-15 01:12:00 +03:00
dataToDumpFile(dumpFP, "<th>%s</th>" % getUnicode(cgi.escape(column).encode("ascii", "xmlcharrefreplace")))
2008-10-15 19:38:22 +04:00
field += 1
2013-10-19 22:54:52 +04:00
if conf.dumpFormat == DUMP_FORMAT.HTML:
dataToDumpFile(dumpFP, "\n</tr>\n</thead>\n<tbody>\n")
2012-02-16 18:42:28 +04:00
self._write("|\n%s" % separator)
2012-11-28 14:16:00 +04:00
if conf.dumpFormat == DUMP_FORMAT.CSV:
dataToDumpFile(dumpFP, "\n" if not appendToFile else "")
2008-10-15 19:38:22 +04:00
2012-11-28 14:16:00 +04:00
elif conf.dumpFormat == DUMP_FORMAT.SQLITE:
rtable.beginTransaction()
if count > TRIM_STDOUT_DUMP_SIZE:
2011-12-23 00:54:20 +04:00
warnMsg = "console output will be trimmed to "
warnMsg += "last %d rows due to " % TRIM_STDOUT_DUMP_SIZE
warnMsg += "large table size"
logger.warning(warnMsg)
for i in xrange(count):
console = (i >= count - TRIM_STDOUT_DUMP_SIZE)
2008-10-15 19:38:22 +04:00
field = 1
2010-09-24 17:19:35 +04:00
values = []
2008-10-15 19:38:22 +04:00
if conf.dumpFormat == DUMP_FORMAT.HTML:
2013-10-19 22:54:52 +04:00
dataToDumpFile(dumpFP, "<tr>")
2008-10-15 19:38:22 +04:00
for column in columns:
if column != "__infos__":
info = tableValues[column]
if len(info["values"]) <= i:
continue
if info["values"][i] is None:
value = u''
else:
value = getUnicode(info["values"][i])
2012-08-21 13:30:01 +04:00
value = DUMP_REPLACEMENTS.get(value, value)
2008-10-15 19:38:22 +04:00
2010-09-24 17:19:35 +04:00
values.append(value)
2008-10-15 19:38:22 +04:00
maxlength = int(info["length"])
blank = " " * (maxlength - getConsoleLength(value))
2012-07-14 13:23:22 +04:00
self._write("| %s%s" % (value, blank), newline=False, console=console)
2008-10-15 19:38:22 +04:00
2013-01-17 14:37:45 +04:00
if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
2013-09-30 11:33:14 +04:00
try:
2019-05-08 18:21:40 +03:00
mimetype = getText(magic.from_buffer(value, mime=True))
if any(mimetype.startswith(_) for _ in ("application", "image")):
2013-09-30 11:33:14 +04:00
if not os.path.isdir(dumpDbPath):
os.makedirs(dumpDbPath)
2013-09-30 11:33:14 +04:00
2018-02-06 12:48:47 +03:00
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(column)))
2015-12-09 12:07:37 +03:00
filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8)))
2013-09-30 11:33:14 +04:00
warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
logger.warn(warnMsg)
2019-07-10 14:49:41 +03:00
with openFile(filepath, "w+b", None) as f:
2013-09-30 11:33:14 +04:00
_ = safechardecode(value, True)
f.write(_)
2019-07-04 12:07:25 +03:00
2019-01-22 03:20:27 +03:00
except magic.MagicException as ex:
logger.debug(getSafeExString(ex))
2012-11-28 14:16:00 +04:00
if conf.dumpFormat == DUMP_FORMAT.CSV:
if field == fields:
2011-07-03 02:48:56 +04:00
dataToDumpFile(dumpFP, "%s" % safeCSValue(value))
else:
2011-11-30 21:39:41 +04:00
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel))
elif conf.dumpFormat == DUMP_FORMAT.HTML:
2019-05-15 01:12:00 +03:00
dataToDumpFile(dumpFP, "<td>%s</td>" % getUnicode(cgi.escape(value).encode("ascii", "xmlcharrefreplace")))
2008-10-15 19:38:22 +04:00
field += 1
2012-11-28 13:58:18 +04:00
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
2011-12-27 15:25:40 +04:00
try:
rtable.insert(values)
except SqlmapValueException:
2011-12-27 15:25:40 +04:00
pass
2012-11-28 14:16:00 +04:00
elif conf.dumpFormat == DUMP_FORMAT.CSV:
dataToDumpFile(dumpFP, "\n")
2013-10-19 22:54:52 +04:00
elif conf.dumpFormat == DUMP_FORMAT.HTML:
dataToDumpFile(dumpFP, "</tr>\n")
2010-09-24 17:19:35 +04:00
2012-02-16 18:42:28 +04:00
self._write("|", console=console)
2012-02-16 18:42:28 +04:00
self._write("%s\n" % separator)
2008-10-15 19:38:22 +04:00
2012-11-28 13:58:18 +04:00
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
rtable.endTransaction()
2012-07-13 17:22:08 +04:00
logger.info("table '%s.%s' dumped to sqlite3 database '%s'" % (db, table, replication.dbpath))
elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML):
if conf.dumpFormat == DUMP_FORMAT.HTML:
2013-10-19 22:54:52 +04:00
dataToDumpFile(dumpFP, "</tbody>\n</table>\n</body>\n</html>")
else:
dataToDumpFile(dumpFP, "\n")
2008-10-15 19:38:22 +04:00
dumpFP.close()
msg = "table '%s.%s' dumped to %s file '%s'" % (db, table, conf.dumpFormat, dumpFileName)
if not warnFile:
logger.info(msg)
else:
logger.warn(msg)
2008-10-15 19:38:22 +04:00
def dbColumns(self, dbColumnsDict, colConsider, dbs):
2017-04-10 20:21:22 +03:00
if conf.api:
2013-01-30 19:30:34 +04:00
self._write(dbColumnsDict, content_type=CONTENT_TYPE.COLUMNS)
return
for column in dbColumnsDict.keys():
if colConsider == "1":
2015-09-21 17:41:54 +03:00
colConsiderStr = "s LIKE '%s' were" % unsafeSQLIdentificatorNaming(column)
else:
2013-02-15 19:48:58 +04:00
colConsiderStr = " '%s' was" % unsafeSQLIdentificatorNaming(column)
2019-08-04 02:05:13 +03:00
found = {}
for db, tblData in dbs.items():
for tbl, colData in tblData.items():
for col, dataType in colData.items():
if column.lower() in col.lower():
2019-08-04 02:05:13 +03:00
if db in found:
if tbl in found[db]:
found[db][tbl][col] = dataType
else:
2019-08-04 02:05:13 +03:00
found[db][tbl] = {col: dataType}
else:
2019-08-04 02:05:13 +03:00
found[db] = {}
found[db][tbl] = {col: dataType}
continue
2019-08-04 02:05:13 +03:00
if found:
msg = "column%s found in the " % colConsiderStr
msg += "following databases:"
self._write(msg)
self.dbTableColumns(found)
2019-04-30 15:04:39 +03:00
def sqlQuery(self, query, queryRes):
2013-01-30 19:30:34 +04:00
self.string(query, queryRes, content_type=CONTENT_TYPE.SQL_QUERY)
2012-12-19 18:12:45 +04:00
def rFile(self, fileData):
2013-01-30 19:30:34 +04:00
self.lister("files saved to", fileData, sort=False, content_type=CONTENT_TYPE.FILE_READ)
def registerValue(self, registerData):
2013-02-14 17:17:30 +04:00
self.string("Registry key value data", registerData, content_type=CONTENT_TYPE.REG_READ, sort=False)
2008-10-15 19:38:22 +04:00
# object to manage how to print the retrieved queries output to
# standard output and sessions file
dumper = Dump()