Adapted and merged in patch to support XML output (-x switch) - still in beta.

Minor bug fixes and adjustments.
This commit is contained in:
Bernardo Damele 2010-05-28 16:43:04 +00:00
parent a138dbe5f6
commit 06af405efd
14 changed files with 964 additions and 86 deletions

View File

@ -157,6 +157,9 @@ Krzysztof Kotowicz <kkotowicz@gmail.com>
Nicolas Krassas <krasn@ans.gr>
for reporting a bug
Alex Landa <landa.alex86@gmail.com>
for providing a patch adding support for XML output
Guido Landi <lists@keamera.org>
for reporting a couple of bugs
for the great technical discussions
@ -193,7 +196,7 @@ Enrico Milanese <enricomilanese@gmail.com>
for reporting a bugs when using (-a) a single line User-Agent file
for providing me with some ideas for the PHP backdoor
Alejo Murillo <alex@65535.com>
Alejo Murillo Moya <alex@65535.com>
for suggesting a feature
Roberto Nemirovsky <roberto.paes@gmail.com>

View File

@ -26,7 +26,6 @@ from lib.controller.handler import setHandler
from lib.core.common import getHtmlErrorFp
from lib.core.data import conf
from lib.core.data import kb
from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.settings import SUPPORTED_DBMS
from lib.techniques.blind.timebased import timeTest
@ -69,53 +68,53 @@ def action():
# Techniques options
if conf.stackedTest:
dumper.string("stacked queries support", stackedTest())
conf.dumper.technic("stacked queries support", stackedTest())
if conf.timeTest:
dumper.string("time based blind sql injection payload", timeTest())
conf.dumper.technic("time based blind sql injection payload", timeTest())
if ( conf.unionUse or conf.unionTest ) and not kb.unionPosition:
dumper.string("valid union", unionTest())
conf.dumper.technic("valid union", unionTest())
# Enumeration options
if conf.getBanner:
dumper.string("banner", conf.dbmsHandler.getBanner())
conf.dumper.banner(conf.dbmsHandler.getBanner())
if conf.getCurrentUser:
dumper.string("current user", conf.dbmsHandler.getCurrentUser())
conf.dumper.currentUser(conf.dbmsHandler.getCurrentUser())
if conf.getCurrentDb:
dumper.string("current database", conf.dbmsHandler.getCurrentDb())
conf.dumper.currentDb(conf.dbmsHandler.getCurrentDb())
if conf.isDba:
dumper.string("current user is DBA", conf.dbmsHandler.isDba())
conf.dumper.dba(conf.dbmsHandler.isDba())
if conf.getUsers:
dumper.lister("database management system users", conf.dbmsHandler.getUsers())
conf.dumper.users(conf.dbmsHandler.getUsers())
if conf.getPasswordHashes:
dumper.userSettings("database management system users password hashes",
conf.dumper.userSettings("database management system users password hashes",
conf.dbmsHandler.getPasswordHashes(), "password hash")
if conf.getPrivileges:
dumper.userSettings("database management system users privileges",
conf.dumper.userSettings("database management system users privileges",
conf.dbmsHandler.getPrivileges(), "privilege")
if conf.getRoles:
dumper.userSettings("database management system users roles",
conf.dumper.userSettings("database management system users roles",
conf.dbmsHandler.getRoles(), "role")
if conf.getDbs:
dumper.lister("available databases", conf.dbmsHandler.getDbs())
conf.dumper.dbs(conf.dbmsHandler.getDbs())
if conf.getTables:
dumper.dbTables(conf.dbmsHandler.getTables())
conf.dumper.dbTables(conf.dbmsHandler.getTables())
if conf.getColumns:
dumper.dbTableColumns(conf.dbmsHandler.getColumns())
conf.dumper.dbTableColumns(conf.dbmsHandler.getColumns())
if conf.dumpTable:
dumper.dbTableValues(conf.dbmsHandler.dumpTable())
conf.dumper.dbTableValues(conf.dbmsHandler.dumpTable())
if conf.dumpAll:
conf.dbmsHandler.dumpAll()
@ -124,7 +123,7 @@ def action():
conf.dbmsHandler.search()
if conf.query:
dumper.string(conf.query, conf.dbmsHandler.sqlQuery(conf.query))
conf.dumper.query(conf.query, conf.dbmsHandler.sqlQuery(conf.query))
if conf.sqlShell:
conf.dbmsHandler.sqlShell()
@ -135,7 +134,7 @@ def action():
# File system options
if conf.rFile:
dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)
conf.dumper.rFile(conf.rFile, conf.dbmsHandler.readFile(conf.rFile))
if conf.wFile:
conf.dbmsHandler.writeFile(conf.wFile, conf.dFile, conf.wFileType)
@ -158,7 +157,7 @@ def action():
# Windows registry options
if conf.regRead:
dumper.string("Registry key value data", conf.dbmsHandler.regRead())
conf.dumper.registerValue(conf.dbmsHandler.regRead())
if conf.regAdd:
conf.dbmsHandler.regAdd()

View File

@ -53,9 +53,17 @@ class Dump:
conf.loggedToOut = True
def __formatString(self, string):
string = unicode(string)
string = string.replace("__NEWLINE__", "\n").replace("__TAB__", "\t")
string = string.replace("__START__", "").replace("__STOP__", "")
string = string.replace("__DEL__", ", ")
return string
def setOutputFile(self):
self.__outputFile = "%s%slog" % (conf.outputPath, os.sep)
self.__outputFP = codecs.open(self.__outputFile, "a", conf.dataEncoding)
self.__outputFP = codecs.open(self.__outputFile, "ab", conf.dataEncoding)
def string(self, header, data, sort=True):
if isinstance(data, (list, tuple, set)):
@ -66,9 +74,7 @@ class Dump:
data = unicode(data)
if data:
data = data.replace("__NEWLINE__", "\n").replace("__TAB__", "\t")
data = data.replace("__START__", "").replace("__STOP__", "")
data = data.replace("__DEL__", ", ")
data = self.__formatString(data)
if "\n" in data:
self.__write("%s:\n---\n%s\n---\n" % (header, data))
@ -98,6 +104,24 @@ class Dump:
if elements:
self.__write("")
def technic(self,header,data):
self.string(header, data)
def banner(self,data):
self.string("banner", data)
def currentUser(self,data):
self.string("current user", data)
def currentDb(self,data):
self.string("current database", data)
def dba(self,data):
self.string("current user is DBA", data)
def users(self,users):
self.lister("database management system users", users)
def userSettings(self, header, userSettings, subHeader):
self.__areAdmins = set()
@ -125,35 +149,8 @@ class Dump:
self.__write(" %s: %s" % (subHeader, setting))
print
def dbColumns(self, dbColumns, colConsider, dbs):
for column in dbColumns.keys():
if colConsider == "1":
colConsiderStr = "s like '" + column + "' were"
else:
colConsiderStr = " '%s' was" % column
msg = "Column%s found in the " % colConsiderStr
msg += "following databases:"
self.__write(msg)
printDbs = {}
for db, tblData in dbs.items():
for tbl, colData in tblData.items():
for col, dataType in colData.items():
if column.lower() in col.lower():
if db in printDbs:
if tbl in printDbs[db]:
printDbs[db][tbl][col] = dataType
else:
printDbs[db][tbl] = { col: dataType }
else:
printDbs[db] = {}
printDbs[db][tbl] = { col: dataType }
continue
self.dbTableColumns(printDbs)
def dbs(self,dbs):
self.lister("available databases", dbs)
def dbTables(self, dbTables):
if not isinstance(dbTables, dict):
@ -268,7 +265,7 @@ class Dump:
os.makedirs(dumpDbPath, 0755)
dumpFileName = "%s%s%s.csv" % (dumpDbPath, os.sep, table)
dumpFP = codecs.open(dumpFileName, "w", conf.dataEncoding)
dumpFP = codecs.open(dumpFileName, "wb", conf.dataEncoding)
count = int(tableValues["__infos__"]["count"])
separator = ""
@ -350,6 +347,45 @@ class Dump:
logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName))
def dbColumns(self, dbColumns, colConsider, dbs):
for column in dbColumns.keys():
if colConsider == "1":
colConsiderStr = "s like '" + column + "' were"
else:
colConsiderStr = " '%s' was" % column
msg = "Column%s found in the " % colConsiderStr
msg += "following databases:"
self.__write(msg)
printDbs = {}
for db, tblData in dbs.items():
for tbl, colData in tblData.items():
for col, dataType in colData.items():
if column.lower() in col.lower():
if db in printDbs:
if tbl in printDbs[db]:
printDbs[db][tbl][col] = dataType
else:
printDbs[db][tbl] = { col: dataType }
else:
printDbs[db] = {}
printDbs[db][tbl] = { col: dataType }
continue
self.dbTableColumns(printDbs)
def query(self, query, queryRes):
self.string(query, queryRes)
def rFile(self,filePath,fileData):
self.string("%s file saved to" % filePath,fileData,sort=False)
def registerValue(self,registerData):
self.string("Registry key value data", registerData,sort=False)
# object to manage how to print the retrieved queries output to
# standard output and sessions file
dumper = Dump()

View File

@ -110,8 +110,6 @@ optDict = {
"limitStop": "integer",
"firstChar": "integer",
"lastChar": "integer",
"getNumOfTables": "integer",
"getNumOfDBs": "integer",
"query": "string",
"sqlShell": "boolean"
},

View File

@ -37,6 +37,7 @@ from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import resumeConfKb
from lib.core.xmldump import dumper as xmldumper
def __setRequestParams():
"""
@ -202,6 +203,14 @@ def __createDumpDir():
if not os.path.isdir(conf.dumpPath):
os.makedirs(conf.dumpPath, 0755)
def __configureDumper():
if conf.xmlFile:
conf.dumper = xmldumper
else:
conf.dumper = dumper
conf.dumper.setOutputFile()
def __createTargetDirs():
"""
Create the output directory.
@ -215,10 +224,9 @@ def __createTargetDirs():
if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755)
dumper.setOutputFile()
__createDumpDir()
__createFilesDir()
__configureDumper()
def initTargetEnv():
"""

526
lib/core/xmldump.py Normal file
View File

@ -0,0 +1,526 @@
#!/usr/bin/env python
import codecs
import re
import xml.sax.saxutils as saxutils
from xml.dom.minidom import Document
from lib.core.data import conf
from lib.core.data import logger
from lib.core.exception import sqlmapFilePathException
TECHNIC_ELEM_NAME = "Technic"
TECHNICS_ELEM_NAME = "Technics"
BANNER_ELEM_NAME = "Banner"
COLUMNS_ELEM_NAME = "DatabaseColumns"
COLUMN_ELEM_NAME = "Column"
CELL_ELEM_NAME = "Cell"
COLUMN_ATTR = "column"
ROW_ELEM_NAME = "Row"
TABLES_ELEM_NAME = "tables"
DATABASE_COLUMNS_ELEM = "DB"
DB_TABLES_ELEM_NAME = "DBTables"
DB_TABLE_ELEM_NAME = "DBTable"
IS_DBA_ELEM_NAME = "isDBA"
FILE_CONTENT_ELEM_NAME = "FileContent"
DB_ATTR = "db"
UNKNOWN_COLUMN_TYPE= "unknown"
USER_SETTINGS_ELEM_NAME = "UserSettings"
USER_SETTING_ELEM_NAME = "UserSetting"
USERS_ELEM_NAME = "Users"
USER_ELEM_NAME = "User"
DB_USER_ELEM_NAME = "DBUser"
SETTINGS_ELEM_NAME = "Settings"
DBS_ELEM_NAME = "DBs"
DB_NAME_ELEM_NAME = "DBName"
DATABASE_ELEM_NAME = "Database"
TABLE_ELEM_NAME = "Table"
DB_TABLE_VALUES_ELEM_NAME = "DBTableValues"
DB_VALUES_ELEM = "DBValues"
QUERIES_ELEM_NAME = "Queries"
QUERY_ELEM_NAME = "Query"
REGISTERY_ENTRIES_ELEM_NAME = "RegistryEntries"
REGISTER_DATA_ELEM_NAME = "RegisterData"
DEFAULT_DB = "All"
MESSAGE_ELEM = "Message"
MESSAGES_ELEM_NAME = "Messages"
ERROR_ELEM_NAME = "Error"
LST_ELEM_NAME = "List"
LSTS_ELEM_NAME = "Lists"
CURRENT_USER_ELEM_NAME = "CurrentUser"
CURRENT_DB_ELEM_NAME = "CurrentDB"
MEMBER_ELEM = "Member"
ADMIN_USER = "Admin"
REGULAR_USER = "User"
STATUS_ELEM_NAME = "Status"
RESULTS_ELEM_NAME = "Results"
UNHANDLED_PROBLEM_TYPE = "Unhandled"
NAME_ATTR = "name"
TYPE_ATTR = "type"
VALUE_ATTR = "value"
SUCESS_ATTR = "success"
ENCODING = "utf-8"
NAME_SPACE_ATTR = 'http://www.w3.org/2001/XMLSchema-instance'
XMLNS_ATTR = "xmlns:xsi"
SCHEME_NAME = "sqlmap.xsd"
SCHEME_NAME_ATTR = "xsi:noNamespaceSchemaLocation"
CHARACTERS_TO_ENCODE = range(32) + range(127, 256)
ENTITIES = {'"':'&quot;',"'":"&apos;"}
class XMLDump:
'''
This class purpose is to dump the data into an xml format.
The format of the xml file is described in the scheme file xml/sqlmap.xsd
'''
def __init__(self):
self.__outputFile = None
self.__outputFP = None
self.__root = None
self.__doc = Document()
def __addToRoot(self,element):
'''
Adds element to the root element
'''
self.__root.appendChild(element)
def __write(self, data, n=True):
'''
Writes the data into the file
'''
if n:
self.__outputFP.write("%s\n" % data)
else:
self.__outputFP.write("%s " % data)
self.__outputFP.flush()
conf.loggedToOut = True
def __getRootChild(self,elemName):
'''
Returns the child of the root with the described name
'''
elements = self.__root.getElementsByTagName(elemName)
if elements :
return elements[0]
return elements
def __createTextNode(self,data):
'''
Creates a text node with utf8 data inside.
The text is escaped to an fit the xml text format.
'''
if data is None :
return self.__doc.createTextNode(unicode("","utf-8"))
else :
string = self.__formatString(data)
escaped_data = saxutils.escape(unicode(string), ENTITIES)
return self.__doc.createTextNode(unicode(escaped_data, "utf-8"))
def __createAttribute(self,attrName,attrValue):
'''
Creates an attribute node with utf8 data inside.
The text is escaped to an fit the xml text format.
'''
attr = self.__doc.createAttribute(attrName)
if attrValue is None :
attr.nodeValue = unicode("","utf-8")
else :
escaped_data = unicode(attrValue)
attr.nodeValue = unicode(escaped_data,"utf-8")
return attr
def __formatString(self, string):
string = unicode(string)
string = string.replace("__NEWLINE__", "\n").replace("__TAB__", "\t")
string = string.replace("__START__", "").replace("__STOP__", "")
string = string.replace("__DEL__", ", ")
return string
def string(self, header, data, sort=True):
'''
Adds string element to the xml.
'''
if isinstance(data, (list, tuple, set)):
self.lister(header, data, sort)
return
messagesElem = self.__getRootChild(MESSAGES_ELEM_NAME)
if (not(messagesElem)):
messagesElem = self.__doc.createElement(MESSAGES_ELEM_NAME)
self.__addToRoot(messagesElem)
if data:
data = self.__formatString(data)
else :
data = ""
elem = self.__doc.createElement(MESSAGE_ELEM)
elem.setAttributeNode(self.__createAttribute(TYPE_ATTR, header))
elem.appendChild(self.__createTextNode(data))
messagesElem.appendChild(elem)
def lister(self, header, elements, sort=True):
'''
Adds information formatted as list element
'''
lstElem = self.__doc.createElement(LST_ELEM_NAME)
lstElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, header))
if elements:
if sort:
try:
elements = set(elements)
elements = list(elements)
elements.sort(key=lambda x: x.lower())
except:
pass
for element in elements:
memberElem = self.__doc.createElement(MEMBER_ELEM)
lstElem.appendChild(memberElem)
if isinstance(element, basestring):
memberElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, "string"))
memberElem.appendChild(self.__createTextNode(element))
elif isinstance(element, (list, tuple, set)):
memberElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, "list"))
for e in element :
memberElemStr = self.__doc.createElement(MEMBER_ELEM)
memberElemStr.setAttributeNode(self.__createAttribute(TYPE_ATTR, "string"))
memberElemStr.appendChild(self.__createTextNode(unicode(e)))
memberElem.appendChild(memberElemStr)
listsElem = self.__getRootChild(LSTS_ELEM_NAME)
if not(listsElem):
listsElem = self.__doc.createElement(LSTS_ELEM_NAME)
self.__addToRoot(listsElem)
listsElem.appendChild(lstElem)
def technic(self,technicType,data):
'''
Adds information about the technic used to extract data from the db
'''
technicElem = self.__doc.createElement(TECHNIC_ELEM_NAME)
technicElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, technicType))
textNode = self.__createTextNode(data)
technicElem.appendChild(textNode)
technicsElem = self.__getRootChild(TECHNICS_ELEM_NAME)
if not(technicsElem):
technicsElem = self.__doc.createElement(TECHNICS_ELEM_NAME)
self.__addToRoot(technicsElem)
technicsElem.appendChild(technicElem)
def banner(self,data):
'''
Adds information about the database banner to the xml.
The banner contains information about the type and the version of the database.
'''
bannerElem = self.__doc.createElement(BANNER_ELEM_NAME)
bannerElem.appendChild(self.__createTextNode(data))
self.__addToRoot(bannerElem)
def currentUser(self,data):
'''
Adds information about the current database user to the xml
'''
currentUserElem = self.__doc.createElement(CURRENT_USER_ELEM_NAME)
textNode = self.__createTextNode(data)
currentUserElem.appendChild(textNode)
self.__addToRoot(currentUserElem)
def currentDb(self,data):
'''
Adds information about the current database is use to the xml
'''
currentDBElem = self.__doc.createElement(CURRENT_DB_ELEM_NAME)
textNode = self.__createTextNode(data)
currentDBElem.appendChild(textNode)
self.__addToRoot(currentDBElem)
def dba(self,isDBA):
'''
Adds information to the xml that indicates whether the user has DBA privileges
'''
isDBAElem = self.__doc.createElement(IS_DBA_ELEM_NAME)
isDBAElem.setAttributeNode(self.__createAttribute(VALUE_ATTR, unicode(isDBA)))
self.__addToRoot(isDBAElem)
def users(self,users):
'''
Adds a list of the existing users to the xml
'''
usersElem = self.__doc.createElement(USERS_ELEM_NAME)
if isinstance(users, basestring):
users = [users]
if users:
for user in users:
userElem = self.__doc.createElement(DB_USER_ELEM_NAME)
usersElem.appendChild(userElem)
userElem.appendChild(self.__createTextNode(user))
self.__addToRoot(usersElem)
def dbs(self, dbs):
'''
Adds a list of the existing databases to the xml
'''
dbsElem = self.__doc.createElement(DBS_ELEM_NAME)
if dbs:
for db in dbs:
dbElem = self.__doc.createElement(DB_NAME_ELEM_NAME)
dbsElem.appendChild(dbElem)
dbElem.appendChild(self.__createTextNode(db))
self.__addToRoot(dbsElem)
def userSettings(self, header, userSettings, subHeader):
'''
Adds information about the user's settings to the xml.
The information can be user's passwords, privileges and etc..
'''
self.__areAdmins = set()
userSettingsElem = self.__getRootChild(USER_SETTINGS_ELEM_NAME)
if (not(userSettingsElem)):
userSettingsElem = self.__doc.createElement(USER_SETTINGS_ELEM_NAME)
self.__addToRoot(userSettingsElem)
userSettingElem = self.__doc.createElement(USER_SETTING_ELEM_NAME)
userSettingElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, header))
if isinstance(userSettings, (tuple, list, set)):
self.__areAdmins = userSettings[1]
userSettings = userSettings[0]
users = userSettings.keys()
users.sort(key=lambda x: x.lower())
for user in users:
userElem = self.__doc.createElement(USER_ELEM_NAME)
userSettingElem.appendChild(userElem)
if user in self.__areAdmins:
userElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, ADMIN_USER))
else:
userElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, REGULAR_USER))
settings = userSettings[user]
settings.sort()
for setting in settings:
settingsElem = self.__doc.createElement(SETTINGS_ELEM_NAME)
settingsElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, subHeader))
settingTextNode = self.__createTextNode(setting)
settingsElem.appendChild(settingTextNode)
userElem.appendChild(settingsElem)
userSettingsElem.appendChild(userSettingElem)
def dbTables(self, dbTables):
'''
Adds information of the existing db tables to the xml
'''
if not isinstance(dbTables, dict):
self.string(TABLES_ELEM_NAME, dbTables)
return
dbTablesElem = self.__doc.createElement(DB_TABLES_ELEM_NAME)
for db, tables in dbTables.items():
tables.sort(key=lambda x: x.lower())
dbElem = self.__doc.createElement(DATABASE_ELEM_NAME)
dbElem.setAttributeNode(self.__createAttribute(NAME_ATTR,db))
dbTablesElem.appendChild(dbElem)
for table in tables:
tableElem = self.__doc.createElement(DB_TABLE_ELEM_NAME)
tableElem.appendChild(self.__createTextNode(table))
dbElem.appendChild(tableElem)
self.__addToRoot(dbTablesElem)
def dbTableColumns(self, tableColumns):
'''
Adds information about the columns of the existing tables to the xml
'''
columnsElem = self.__getRootChild(COLUMNS_ELEM_NAME)
if not(columnsElem):
columnsElem = self.__doc.createElement(COLUMNS_ELEM_NAME)
for db, tables in tableColumns.items():
if not db:
db = DEFAULT_DB
dbElem = self.__doc.createElement(DATABASE_COLUMNS_ELEM)
dbElem.setAttributeNode(self.__createAttribute(NAME_ATTR, db))
columnsElem.appendChild(dbElem)
for table, columns in tables.items():
tableElem = self.__doc.createElement(TABLE_ELEM_NAME)
tableElem.setAttributeNode(self.__createAttribute(NAME_ATTR, table))
colList = columns.keys()
colList.sort(key=lambda x: x.lower())
for column in colList:
colType = columns[column]
colElem = self.__doc.createElement(COLUMN_ELEM_NAME)
if colType is not None:
colElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, colType))
else :
colElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, UNKNOWN_COLUMN_TYPE))
colElem.appendChild(self.__createTextNode(column))
tableElem.appendChild(colElem)
self.__addToRoot(columnsElem)
def dbTableValues(self, tableValues):
'''
Adds the values of specific table to the xml.
The values are organized according to the relevant row and column.
'''
tableElem = self.__doc.createElement(DB_TABLE_VALUES_ELEM_NAME)
if (tableValues is not None):
db = tableValues["__infos__"]["db"]
if not db:
db = "All"
table = tableValues["__infos__"]["table"]
count = int(tableValues["__infos__"]["count"])
columns = tableValues.keys()
columns.sort(key=lambda x: x.lower())
tableElem.setAttributeNode(self.__createAttribute(DB_ATTR, db))
tableElem.setAttributeNode(self.__createAttribute(NAME_ATTR, table))
for i in range(count):
rowElem = self.__doc.createElement(ROW_ELEM_NAME)
tableElem.appendChild(rowElem)
for column in columns:
if column != "__infos__":
info = tableValues[column]
value = info["values"][i]
if re.search("^[\ *]*$", value):
value = "NULL"
cellElem = self.__doc.createElement(CELL_ELEM_NAME)
cellElem.setAttributeNode(self.__createAttribute(COLUMN_ATTR, column))
cellElem.appendChild(self.__createTextNode(value))
rowElem.appendChild(cellElem)
dbValuesElem = self.__getRootChild(DB_VALUES_ELEM)
if (not(dbValuesElem)):
dbValuesElem = self.__doc.createElement(DB_VALUES_ELEM)
self.__addToRoot(dbValuesElem)
dbValuesElem.appendChild(tableElem)
logger.info("Table '%s.%s' dumped to XML file" % (db, table))
def dbColumns(self, dbColumns, colConsider, dbs):
'''
Adds information about the columns
'''
for column in dbColumns.keys():
printDbs = {}
for db, tblData in dbs.items():
for tbl, colData in tblData.items():
for col, dataType in colData.items():
if column in col:
if db in printDbs:
if tbl in printDbs[db]:
printDbs[db][tbl][col] = dataType
else:
printDbs[db][tbl] = { col: dataType }
else:
printDbs[db] = {}
printDbs[db][tbl] = { col: dataType }
continue
self.dbTableColumns(printDbs)
def query(self,query,queryRes):
'''
Adds details of an executed query to the xml.
The query details are the query itself and it's results.
'''
queryElem = self.__doc.createElement(QUERY_ELEM_NAME)
queryElem.setAttributeNode(self.__createAttribute(VALUE_ATTR, query))
queryElem.appendChild(self.__createTextNode(queryRes))
queriesElem = self.__getRootChild(QUERIES_ELEM_NAME)
if (not(queriesElem)):
queriesElem = self.__doc.createElement(QUERIES_ELEM_NAME)
self.__addToRoot(queriesElem)
queriesElem.appendChild(queryElem)
def registerValue(self,registerData):
'''
Adds information about an extracted registry key to the xml
'''
registerElem = self.__doc.createElement(REGISTER_DATA_ELEM_NAME)
registerElem.appendChild(self.__createTextNode(registerData))
registriesElem = self.__getRootChild(REGISTERY_ENTRIES_ELEM_NAME)
if (not(registriesElem)):
registriesElem = self.__doc.createElement(REGISTERY_ENTRIES_ELEM_NAME)
self.__addToRoot(registriesElem)
registriesElem.appendChild(registerElem)
def rFile(self, filePath, data):
'''
Adds an extracted file's content to the xml
'''
fileContentElem = self.__doc.createElement(FILE_CONTENT_ELEM_NAME)
fileContentElem.setAttributeNode(self.__createAttribute(NAME_ATTR, filePath))
fileContentElem.appendChild(self.__createTextNode(data))
self.__addToRoot(fileContentElem)
def setOutputFile(self):
'''
Initiates the xml file from the configuration.
'''
if (conf.xmlFile) :
try :
self.__outputFile = conf.xmlFile
self.__outputFP = codecs.open(self.__outputFile, "ab", conf.dataEncoding)
self.__root = self.__doc.createElementNS(NAME_SPACE_ATTR, RESULTS_ELEM_NAME)
self.__root.setAttributeNode(self.__createAttribute(XMLNS_ATTR,NAME_SPACE_ATTR))
self.__root.setAttributeNode(self.__createAttribute(SCHEME_NAME_ATTR,SCHEME_NAME))
self.__doc.appendChild(self.__root)
except IOError, e:
raise sqlmapFilePathException("Wrong filename provided for saving the xml file: %s" % conf.xmlFile)
def finish(self, resultStatus, resultMsg=""):
'''
Finishes the dumper operation:
1. Adds the session status to the xml
2. Writes the xml to the file
3. Closes the xml file
'''
if ((self.__outputFP is not None) and not(self.__outputFP.closed)):
statusElem = self.__doc.createElement(STATUS_ELEM_NAME)
statusElem.setAttributeNode(self.__createAttribute(SUCESS_ATTR,unicode(resultStatus)))
if not(resultStatus) :
errorElem = self.__doc.createElement(ERROR_ELEM_NAME)
if (isinstance(resultMsg, Exception)):
errorElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, type(resultMsg).__name__))
else :
errorElem.setAttributeNode(self.__createAttribute(TYPE_ATTR, UNHANDLED_PROBLEM_TYPE))
errorElem.appendChild(self.__createTextNode(unicode(resultMsg)))
statusElem.appendChild(errorElem)
self.__addToRoot(statusElem)
self.__write(self.__doc.toprettyxml(encoding=ENCODING))
self.__outputFP.close()
def closeDumper(status, msg=""):
"""
Closes the dumper of the session
"""
if hasattr(conf, "dumper") and hasattr(conf.dumper, "finish"):
conf.dumper.finish(status, msg)
dumper = XMLDump()

View File

@ -414,6 +414,9 @@ def cmdLineParser():
# Miscellaneous options
miscellaneous = OptionGroup(parser, "Miscellaneous")
miscellaneous.add_option("-x", dest="xmlFile",
help="Dump the data into an XML file")
miscellaneous.add_option("-s", dest="sessionFile",
help="Save and resume all data retrieved "
"on a session file")

View File

@ -26,7 +26,6 @@ from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion
from lib.takeover.udf import UDF
@ -90,7 +89,7 @@ class Abstraction(Web, UDF, xp_cmdshell):
output = self.evalCmd(cmd)
if output:
dumper.string("command standard output", output)
conf.dumper.string("command standard output", output)
else:
print "No output"
else:

View File

@ -31,7 +31,6 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.dump import dumper
from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapUnsupportedFeatureException
@ -370,7 +369,7 @@ class UDF:
output = self.udfEvalCmd(cmd, udfName=udfToCall)
if output:
dumper.string("return value", output)
conf.dumper.string("return value", output)
else:
print "No return value"
else:

View File

@ -30,12 +30,12 @@ from lib.core.common import parsePasswordHash
from lib.core.common import readInput
from lib.core.common import safeStringFormat
from lib.core.convert import urlencode
from lib.core.convert import utf8decode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.data import temp
from lib.core.dump import dumper
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUnsupportedFeatureException
@ -80,7 +80,7 @@ class Enumeration:
if not kb.data.banner:
if conf.unionUse or conf.unionTest:
dumper.string("valid union", unionTest())
conf.dumper.technic("valid union", unionTest())
query = queries[kb.dbms].banner
kb.data.banner = inject.getValue(query)
@ -775,7 +775,7 @@ class Enumeration:
plusOne = True
else:
plusOne = False
indexRange = getRange(count, plusOne=plusOne)
indexRange = getRange(count)
for index in indexRange:
if kb.dbms in ("SQLite", "Firebird"):
@ -1183,7 +1183,7 @@ class Enumeration:
data = self.dumpTable()
if data:
dumper.dbTableValues(data)
conf.dumper.dbTableValues(data)
def dumpFoundColumn(self, dbs, foundCols, colConsider):
if not dbs:
@ -1192,7 +1192,7 @@ class Enumeration:
logger.warn(warnMsg)
return
dumper.dbColumns(foundCols, colConsider, dbs)
conf.dumper.dbColumns(foundCols, colConsider, dbs)
message = "do you want to dump entries? [Y/n] "
output = readInput(message, default="Y")
@ -1254,7 +1254,7 @@ class Enumeration:
data = self.dumpTable()
if data:
dumper.dbTableValues(data)
conf.dumper.dbTableValues(data)
def searchDb(self):
foundDbs = []
@ -1620,10 +1620,10 @@ class Enumeration:
def search(self):
if conf.db:
dumper.lister("found databases", self.searchDb())
conf.dumper.lister("found databases", self.searchDb())
if conf.tbl:
dumper.dbTables(self.searchTable())
conf.dumper.dbTables(self.searchTable())
if conf.col:
self.searchColumn()
@ -1691,6 +1691,7 @@ class Enumeration:
try:
query = raw_input("sql-shell> ")
query = utf8decode(query)
except KeyboardInterrupt:
print
errMsg = "user aborted"
@ -1710,7 +1711,7 @@ class Enumeration:
output = self.sqlQuery(query)
if output and output != "Quit":
dumper.string(query, output)
conf.dumper.query(query, output)
elif not output:
pass

View File

@ -442,10 +442,12 @@ regType =
[Miscellaneous]
# Dump the data into an XML file.
xmlFile =
# Save and resume all data retrieved on a session file.
sessionFile =
# Flush session file for current target.
flushSession = False

View File

@ -52,6 +52,7 @@ from lib.core.data import paths
from lib.core.exception import exceptionsTuple
from lib.core.exception import unhandledException
from lib.core.option import init
from lib.core.xmldump import closeDumper
from lib.parse.cmdline import cmdLineParser
def modulePath():
@ -87,22 +88,29 @@ def main():
except exceptionsTuple, e:
e = unicode(e)
logger.error(e)
closeDumper(False, e)
except KeyboardInterrupt:
except KeyboardInterrupt, e:
print
errMsg = "user aborted"
logger.error(errMsg)
closeDumper(False, e)
except EOFError:
except EOFError, e:
print
errMsg = "exit"
logger.error(errMsg)
closeDumper(False, e)
except:
print
errMsg = unhandledException()
logger.error(errMsg)
traceback.print_exc()
closeDumper(False, errMsg)
else:
closeDumper(True)
print "\n[*] shutting down at: %s\n" % time.strftime("%X")

View File

@ -1,14 +1,31 @@
[Databases]
information_schema
mysql
public
master
[Tables]
CHARACTER_SETS
COLLATION_CHARACTER_SET_APPLICABILITY
COLLATIONS
COLUMN_PRIVILEGES
COLUMNS
ENGINES
EVENTS
FILES
GLOBAL_STATUS
GLOBAL_VARIABLES
KEY_COLUMN_USAGE
PARTITIONS
PLUGINS
PROCESSLIST
PROFILING
REFERENTIAL_CONSTRAINTS
ROUTINES
SCHEMA_PRIVILEGES
SCHEMATA
SESSION_STATUS
SESSION_VARIABLES
STATISTICS
TABLE_CONSTRAINTS
TABLE_PRIVILEGES
@ -16,8 +33,3 @@ TABLES
TRIGGERS
USER_PRIVILEGES
VIEWS
[Databases]
information_schema
mysql
iabc

284
xml/sqlmap.xsd Normal file
View File

@ -0,0 +1,284 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Results">
<xs:complexType>
<xs:all>
<xs:element ref="Messages" minOccurs="0" />
<xs:element ref="Banner" minOccurs="0"/>
<xs:element ref="CurrentUser" minOccurs="0"/>
<xs:element ref="CurrentDB" minOccurs="0"/>
<xs:element ref="isDBA" minOccurs="0"/>
<xs:element ref="Users" minOccurs="0"/>
<xs:element ref="UserSettings" minOccurs="0"/>
<xs:element ref="DBs" minOccurs="0"/>
<xs:element ref="DBTables" minOccurs="0"/>
<xs:element ref="Technics" minOccurs="0" />
<xs:element ref="Lists" minOccurs="0" />
<xs:element ref="DatabaseColumns" minOccurs="0" />
<xs:element ref="DBValues" minOccurs="0"/>
<xs:element ref="Queries" minOccurs="0"/>
<xs:element ref="RegistryEntries" minOccurs="0"/>
<xs:element ref="FileContent" minOccurs="0"/>
<xs:element ref="Status"/>
</xs:all>
</xs:complexType>
</xs:element>
<!-- Simple Types -->
<xs:element name="Banner" type="xs:string"/>
<xs:element name="CurrentUser" type="xs:string"/>
<xs:element name="CurrentDB" type="xs:string"/>
<!-- File Content -->
<xs:element name="FileContent">
<xs:complexType mixed="true">
<xs:attribute name="name" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<!-- RegistryEntries -->
<xs:element name="RegistryEntries">
<xs:complexType>
<xs:sequence>
<xs:element ref="RegisterData" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="RegisterData" type="xs:string"/>
<!-- Queries -->
<xs:element name="Queries">
<xs:complexType>
<xs:sequence>
<xs:element ref="Query" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Query">
<xs:complexType mixed="true">
<xs:attribute name="value" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<!-- Columns -->
<xs:element name="DatabaseColumns">
<xs:complexType>
<xs:sequence>
<xs:element ref="DB" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DB">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element ref="Table" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="Table">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element ref="Column" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="Column">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<!-- List -->
<xs:element name="Member">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element ref="Member" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="type" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="List">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element ref="Member" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="type" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="Lists">
<xs:complexType>
<xs:sequence>
<xs:element ref="List" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- Technics -->
<xs:element name="Technics">
<xs:complexType>
<xs:sequence>
<xs:element ref="Technic" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Technic">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<!-- Messages -->
<xs:element name="Messages">
<xs:complexType>
<xs:sequence>
<xs:element ref="Message" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Message">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<!-- is DBA -->
<xs:element name="isDBA">
<xs:complexType>
<xs:attribute name="value" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
<!-- Users -->
<xs:element name="Users">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="DBUser"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DBUser" type="xs:string"/>
<!-- User Settings -->
<xs:element name="UserSettings">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="UserSetting"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="UserSetting">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="User"/>
</xs:sequence>
<xs:attribute name="type" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="User">
<xs:complexType>
<xs:sequence>
<xs:element ref="Settings" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="type" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
<xs:element name="Settings">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required"/>
</xs:complexType>
</xs:element>
<!-- Databases -->
<xs:element name="DBs">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="DBName"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DBName" type="xs:NCName"/>
<!-- DB Tables -->
<xs:element name="DBTables">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="Database"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Database">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="DBTable"/>
</xs:sequence>
<xs:attribute name="name" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
<xs:element name="DBTable" type="xs:NCName"/>
<!-- Table Values -->
<xs:element name="DBValues">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="DBTableValues"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DBTableValues">
<xs:complexType>
<xs:sequence>
<xs:element ref="Row" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="db" type="xs:string"/>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="Row">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="Cell"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Cell">
<xs:complexType mixed="true">
<xs:attribute name="column" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
<!-- Status Elements -->
<xs:element name="Status">
<xs:complexType>
<xs:sequence>
<xs:element ref="Error" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="success" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
<xs:element name="Error">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
</xs:schema>