From a63e251b25e107cbb62d4d658b7f6f783dcc74a1 Mon Sep 17 00:00:00 2001 From: Bernardo Damele Date: Tue, 23 Mar 2010 21:26:45 +0000 Subject: [PATCH] Ahead with code refactoring, related to r1502. Fixed svn:keywords propset to all .py files. --- plugins/dbms/access/__init__.py | 263 ++------------------------ plugins/dbms/access/enumeration.py | 43 +++++ plugins/dbms/access/filesystem.py | 39 ++++ plugins/dbms/access/fingerprint.py | 174 +++++++++++++++++ plugins/dbms/access/syntax.py | 88 +++++++++ plugins/dbms/access/takeover.py | 49 +++++ plugins/dbms/firebird/__init__.py | 253 ++----------------------- plugins/dbms/firebird/enumeration.py | 43 +++++ plugins/dbms/firebird/filesystem.py | 39 ++++ plugins/dbms/firebird/fingerprint.py | 165 +++++++++++++++++ plugins/dbms/firebird/syntax.py | 88 +++++++++ plugins/dbms/firebird/takeover.py | 49 +++++ plugins/dbms/mssqlserver/syntax.py | 1 + plugins/dbms/mysql/syntax.py | 1 + plugins/dbms/postgresql/syntax.py | 1 + plugins/dbms/sqlite/__init__.py | 268 ++------------------------- plugins/dbms/sqlite/enumeration.py | 87 +++++++++ plugins/dbms/sqlite/filesystem.py | 39 ++++ plugins/dbms/sqlite/fingerprint.py | 131 +++++++++++++ plugins/dbms/sqlite/syntax.py | 93 ++++++++++ plugins/dbms/sqlite/takeover.py | 49 +++++ 21 files changed, 1216 insertions(+), 747 deletions(-) create mode 100644 plugins/dbms/access/enumeration.py create mode 100644 plugins/dbms/access/filesystem.py create mode 100644 plugins/dbms/access/fingerprint.py create mode 100644 plugins/dbms/access/syntax.py create mode 100644 plugins/dbms/access/takeover.py create mode 100644 plugins/dbms/firebird/enumeration.py create mode 100644 plugins/dbms/firebird/filesystem.py create mode 100644 plugins/dbms/firebird/fingerprint.py create mode 100644 plugins/dbms/firebird/syntax.py create mode 100644 plugins/dbms/firebird/takeover.py create mode 100644 plugins/dbms/sqlite/enumeration.py create mode 100644 plugins/dbms/sqlite/filesystem.py create mode 100644 plugins/dbms/sqlite/fingerprint.py create mode 100644 plugins/dbms/sqlite/syntax.py create mode 100644 plugins/dbms/sqlite/takeover.py diff --git a/plugins/dbms/access/__init__.py b/plugins/dbms/access/__init__.py index 14ac6ab3a..37efd4030 100644 --- a/plugins/dbms/access/__init__.py +++ b/plugins/dbms/access/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -$Id: oracle.py 1003 2010-01-02 02:02:12Z inquisb $ +$Id$ This file is part of the sqlmap project, http://sqlmap.sourceforge.net. @@ -22,266 +22,29 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -import re - -from lib.core.agent import agent -from lib.core.common import formatDBMSfp -from lib.core.common import formatFingerprint -from lib.core.common import getHtmlErrorFp -from lib.core.common import randomInt -from lib.core.data import conf -from lib.core.data import kb -from lib.core.data import logger -from lib.core.exception import sqlmapSyntaxException -from lib.core.exception import sqlmapUnsupportedFeatureException -from lib.core.session import setDbms -from lib.core.settings import ACCESS_ALIASES from lib.core.settings import ACCESS_SYSTEM_DBS from lib.core.unescaper import unescaper -from lib.request import inject -from lib.request.connect import Connect as Request -from plugins.generic.enumeration import Enumeration -from plugins.generic.filesystem import Filesystem -from plugins.generic.fingerprint import Fingerprint +from plugins.dbms.access.enumeration import Enumeration +from plugins.dbms.access.filesystem import Filesystem +from plugins.dbms.access.fingerprint import Fingerprint +from plugins.dbms.access.syntax import Syntax +from plugins.dbms.access.takeover import Takeover from plugins.generic.misc import Miscellaneous -from plugins.generic.takeover import Takeover - -class AccessMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): +class AccessMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ - This class defines Access methods + This class defines Microsoft Access methods """ def __init__(self): self.excludeDbsList = ACCESS_SYSTEM_DBS - Enumeration.__init__(self, "Microsoft Access") + Syntax.__init__(self) + Fingerprint.__init__(self) + Enumeration.__init__(self) Filesystem.__init__(self) + Miscellaneous.__init__(self) Takeover.__init__(self) - + unescaper.setUnescape(AccessMap.unescape) - - @staticmethod - def unescape(expression, quote=True): - if quote: - while True: - index = expression.find("'") - if index == -1: - break - - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "" - - for i in range(firstIndex, lastIndex): - unescaped += "CHR(%d)" % (ord(expression[i])) - if i < lastIndex - 1: - unescaped += "&" - - expression = expression.replace(old, unescaped) - else: - unescaped = "".join("CHR(%d)&" % ord(c) for c in expression) - if unescaped[-1] == "&": - unescaped = unescaped[:-1] - - expression = unescaped - - return expression - - @staticmethod - def escape(expression): - while True: - index = expression.find("CHR(") - if index == -1: - break - - firstIndex = index - index = expression[firstIndex:].find(")") - - if index == -1: - raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression - - lastIndex = firstIndex + index + 1 - old = expression[firstIndex:lastIndex] - oldUpper = old.upper() - oldUpper = oldUpper.lstrip("CHR(").rstrip(")") - oldUpper = oldUpper.split("&") - - escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper]) - expression = expression.replace(old, escaped).replace("'&'", "") - - return expression - - def __sandBoxCheck(self): - # Reference: http://milw0rm.com/papers/198 - retVal = None - table = None - if kb.dbmsVersion and len(kb.dbmsVersion) > 0: - if kb.dbmsVersion[0] in ("97", "2000"): - table = "MSysAccessObjects" - elif kb.dbmsVersion[0] in ("2002-2003", "2007"): - table = "MSysAccessStorage" - if table: - query = agent.prefixQuery(" AND EXISTS(SELECT CURDIR() FROM %s)" % table) - query = agent.postfixQuery(query) - payload = agent.payload(newValue=query) - result = Request.queryPage(payload) - retVal = "not sandboxed" if result else "sandboxed" - - return retVal - - def __sysTablesCheck(self): - infoMsg = "executing system table(s) existance fingerprint" - logger.info(infoMsg) - - # Microsoft Access table reference updated on 01/2010 - sysTables = { - "97": ("MSysModules2", "MSysAccessObjects"), - "2000" : ("!MSysModules2", "MSysAccessObjects"), - "2002-2003" : ("MSysAccessStorage", "!MSysNavPaneObjectIDs"), - "2007" : ("MSysAccessStorage", "MSysNavPaneObjectIDs") - } - # MSysAccessXML is not a reliable system table because it doesn't always exist - # ("Access through Access", p6, should be "normally doesn't exist" instead of "is normally empty") - - for version, tables in sysTables.items(): - exist = True - for table in tables: - negate = False - if table[0] == '!': - negate = True - table = table[1:] - randInt = randomInt() - query = agent.prefixQuery(" AND EXISTS(SELECT * FROM %s WHERE %d=%d)" % (table, randInt, randInt)) - query = agent.postfixQuery(query) - payload = agent.payload(newValue=query) - result = Request.queryPage(payload) - if negate: - result = not result - exist &= result - if not exist: - break - if exist: - return version - - return None - - def getFingerprint(self): - value = "" - wsOsFp = formatFingerprint("web server", kb.headersFp) - - if wsOsFp: - value += "%s\n" % wsOsFp - - if kb.data.banner: - dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp) - - if dbmsOsFp: - value += "%s\n" % dbmsOsFp - - value += "back-end DBMS: " - - if not conf.extensiveFp: - value += "Microsoft Access" - return value - - actVer = formatDBMSfp() + " (%s)" % (self.__sandBoxCheck()) - blank = " " * 15 - value += "active fingerprint: %s" % actVer - - if kb.bannerFp: - banVer = kb.bannerFp["dbmsVersion"] - - if re.search("-log$", kb.data.banner): - banVer += ", logging enabled" - - banVer = formatDBMSfp([banVer]) - value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) - - htmlErrorFp = getHtmlErrorFp() - - if htmlErrorFp: - value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) - - return value - - def checkDbms(self): - if conf.dbms in ACCESS_ALIASES: - setDbms("Microsoft Access") - if not conf.extensiveFp: - return True - - logMsg = "testing Microsoft Access" - logger.info(logMsg) - - payload = agent.fullPayload(" AND VAL(CVAR(1))=1") - result = Request.queryPage(payload) - - if result: - logMsg = "confirming Microsoft Access" - logger.info(logMsg) - - payload = agent.fullPayload(" AND IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0") - result = Request.queryPage(payload) - - if not result: - warnMsg = "the back-end DMBS is not Microsoft Access" - logger.warn(warnMsg) - return False - - setDbms("Microsoft Access") - - if not conf.extensiveFp: - return True - - kb.dbmsVersion = [self.__sysTablesCheck()] - - return True - else: - warnMsg = "the back-end DMBS is not Microsoft Access" - logger.warn(warnMsg) - - return False - - def getPasswordHashes(self): - warnMsg = "on Microsoft Access it is not possible to enumerate the user password hashes" - logger.warn(warnMsg) - - return {} - - def readFile(self, rFile): - errMsg = "on Microsoft Access it is not possible to read files" - raise sqlmapUnsupportedFeatureException, errMsg - - def writeFile(self, wFile, dFile, fileType=None, confirm=True): - errMsg = "on Microsoft Access it is not possible to write files" - raise sqlmapUnsupportedFeatureException, errMsg - - def osCmd(self): - errMsg = "on Microsoft Access it is not possible to execute commands" - raise sqlmapUnsupportedFeatureException, errMsg - - def osShell(self): - errMsg = "on Microsoft Access it is not possible to execute commands" - raise sqlmapUnsupportedFeatureException, errMsg - - def osPwn(self): - errMsg = "on Microsoft Access it is not possible to establish an " - errMsg += "out-of-band connection" - raise sqlmapUnsupportedFeatureException, errMsg - - def osSmb(self): - errMsg = "on Microsoft Access it is not possible to establish an " - errMsg += "out-of-band connection" - raise sqlmapUnsupportedFeatureException, errMsg - - def getBanner(self): - errMsg = "on Microsoft Access it is not possible to get a banner" - raise sqlmapUnsupportedFeatureException, errMsg \ No newline at end of file diff --git a/plugins/dbms/access/enumeration.py b/plugins/dbms/access/enumeration.py new file mode 100644 index 000000000..1598de4d3 --- /dev/null +++ b/plugins/dbms/access/enumeration.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.data import logger + +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def __init__(self): + GenericEnumeration.__init__(self, "Microsoft Access") + + def getBanner(self): + warnMsg = "on Microsoft Access it is not possible to get a banner" + logger.warn(warnMsg) + + return None + + def getPasswordHashes(self): + warnMsg = "on Microsoft Access it is not possible to enumerate the user password hashes" + logger.warn(warnMsg) + + return {} diff --git a/plugins/dbms/access/filesystem.py b/plugins/dbms/access/filesystem.py new file mode 100644 index 000000000..5cb1574ae --- /dev/null +++ b/plugins/dbms/access/filesystem.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapUnsupportedFeatureException + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + def __init__(self): + GenericFilesystem.__init__(self) + + def readFile(self, rFile): + errMsg = "on Microsoft Access it is not possible to read files" + raise sqlmapUnsupportedFeatureException, errMsg + + def writeFile(self, wFile, dFile, fileType=None, confirm=True): + errMsg = "on Microsoft Access it is not possible to write files" + raise sqlmapUnsupportedFeatureException, errMsg diff --git a/plugins/dbms/access/fingerprint.py b/plugins/dbms/access/fingerprint.py new file mode 100644 index 000000000..0997b2bc5 --- /dev/null +++ b/plugins/dbms/access/fingerprint.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +import re + +from lib.core.agent import agent +from lib.core.common import formatDBMSfp +from lib.core.common import formatFingerprint +from lib.core.common import getHtmlErrorFp +from lib.core.common import randomInt +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.session import setDbms +from lib.core.settings import ACCESS_ALIASES +from lib.request.connect import Connect as Request + +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self) + + def __sandBoxCheck(self): + # Reference: http://milw0rm.com/papers/198 + retVal = None + table = None + if kb.dbmsVersion and len(kb.dbmsVersion) > 0: + if kb.dbmsVersion[0] in ("97", "2000"): + table = "MSysAccessObjects" + elif kb.dbmsVersion[0] in ("2002-2003", "2007"): + table = "MSysAccessStorage" + if table: + query = agent.prefixQuery(" AND EXISTS(SELECT CURDIR() FROM %s)" % table) + query = agent.postfixQuery(query) + payload = agent.payload(newValue=query) + result = Request.queryPage(payload) + retVal = "not sandboxed" if result else "sandboxed" + + return retVal + + def __sysTablesCheck(self): + infoMsg = "executing system table(s) existance fingerprint" + logger.info(infoMsg) + + # Microsoft Access table reference updated on 01/2010 + sysTables = { + "97": ("MSysModules2", "MSysAccessObjects"), + "2000" : ("!MSysModules2", "MSysAccessObjects"), + "2002-2003" : ("MSysAccessStorage", "!MSysNavPaneObjectIDs"), + "2007" : ("MSysAccessStorage", "MSysNavPaneObjectIDs") + } + # MSysAccessXML is not a reliable system table because it doesn't always exist + # ("Access through Access", p6, should be "normally doesn't exist" instead of "is normally empty") + + for version, tables in sysTables.items(): + exist = True + for table in tables: + negate = False + if table[0] == '!': + negate = True + table = table[1:] + randInt = randomInt() + query = agent.prefixQuery(" AND EXISTS(SELECT * FROM %s WHERE %d=%d)" % (table, randInt, randInt)) + query = agent.postfixQuery(query) + payload = agent.payload(newValue=query) + result = Request.queryPage(payload) + if negate: + result = not result + exist &= result + if not exist: + break + if exist: + return version + + return None + + def getFingerprint(self): + value = "" + wsOsFp = formatFingerprint("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += "Microsoft Access" + return value + + actVer = formatDBMSfp() + " (%s)" % (self.__sandBoxCheck()) + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp["dbmsVersion"] + + if re.search("-log$", kb.data.banner): + banVer += ", logging enabled" + + banVer = formatDBMSfp([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = getHtmlErrorFp() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if conf.dbms in ACCESS_ALIASES: + setDbms("Microsoft Access") + if not conf.extensiveFp: + return True + + logMsg = "testing Microsoft Access" + logger.info(logMsg) + + payload = agent.fullPayload(" AND VAL(CVAR(1))=1") + result = Request.queryPage(payload) + + if result: + logMsg = "confirming Microsoft Access" + logger.info(logMsg) + + payload = agent.fullPayload(" AND IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0") + result = Request.queryPage(payload) + + if not result: + warnMsg = "the back-end DMBS is not Microsoft Access" + logger.warn(warnMsg) + return False + + setDbms("Microsoft Access") + + if not conf.extensiveFp: + return True + + kb.dbmsVersion = [self.__sysTablesCheck()] + + return True + else: + warnMsg = "the back-end DMBS is not Microsoft Access" + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/access/syntax.py b/plugins/dbms/access/syntax.py new file mode 100644 index 000000000..909086312 --- /dev/null +++ b/plugins/dbms/access/syntax.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapSyntaxException + +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + def __init__(self): + GenericSyntax.__init__(self) + + @staticmethod + def unescape(expression, quote=True): + if quote: + while True: + index = expression.find("'") + if index == -1: + break + + firstIndex = index + 1 + index = expression[firstIndex:].find("'") + + if index == -1: + raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression + + lastIndex = firstIndex + index + old = "'%s'" % expression[firstIndex:lastIndex] + unescaped = "" + + for i in range(firstIndex, lastIndex): + unescaped += "CHR(%d)" % (ord(expression[i])) + if i < lastIndex - 1: + unescaped += "&" + + expression = expression.replace(old, unescaped) + else: + unescaped = "".join("CHR(%d)&" % ord(c) for c in expression) + if unescaped[-1] == "&": + unescaped = unescaped[:-1] + + expression = unescaped + + return expression + + @staticmethod + def escape(expression): + while True: + index = expression.find("CHR(") + if index == -1: + break + + firstIndex = index + index = expression[firstIndex:].find(")") + + if index == -1: + raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression + + lastIndex = firstIndex + index + 1 + old = expression[firstIndex:lastIndex] + oldUpper = old.upper() + oldUpper = oldUpper.lstrip("CHR(").rstrip(")") + oldUpper = oldUpper.split("&") + + escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper]) + expression = expression.replace(old, escaped).replace("'&'", "") + + return expression diff --git a/plugins/dbms/access/takeover.py b/plugins/dbms/access/takeover.py new file mode 100644 index 000000000..2a1f25389 --- /dev/null +++ b/plugins/dbms/access/takeover.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapUnsupportedFeatureException + +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + GenericTakeover.__init__(self) + + def osCmd(self): + errMsg = "on Microsoft Access it is not possible to execute commands" + raise sqlmapUnsupportedFeatureException, errMsg + + def osShell(self): + errMsg = "on Microsoft Access it is not possible to execute commands" + raise sqlmapUnsupportedFeatureException, errMsg + + def osPwn(self): + errMsg = "on Microsoft Access it is not possible to establish an " + errMsg += "out-of-band connection" + raise sqlmapUnsupportedFeatureException, errMsg + + def osSmb(self): + errMsg = "on Microsoft Access it is not possible to establish an " + errMsg += "out-of-band connection" + raise sqlmapUnsupportedFeatureException, errMsg diff --git a/plugins/dbms/firebird/__init__.py b/plugins/dbms/firebird/__init__.py index 9c1da9648..e52386db6 100644 --- a/plugins/dbms/firebird/__init__.py +++ b/plugins/dbms/firebird/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -$Id: oracle.py 1003 2010-01-02 02:02:12Z inquisb $ +$Id$ This file is part of the sqlmap project, http://sqlmap.sourceforge.net. @@ -22,33 +22,17 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -import re - -from lib.core.agent import agent -from lib.core.common import formatDBMSfp -from lib.core.common import formatFingerprint -from lib.core.common import getHtmlErrorFp -from lib.core.common import randomInt, randomRange -from lib.core.data import conf -from lib.core.data import kb -from lib.core.data import logger -from lib.core.exception import sqlmapSyntaxException -from lib.core.exception import sqlmapUnsupportedFeatureException -from lib.core.session import setDbms -from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import FIREBIRD_SYSTEM_DBS from lib.core.unescaper import unescaper -from lib.request import inject -from lib.request.connect import Connect as Request -from plugins.generic.enumeration import Enumeration -from plugins.generic.filesystem import Filesystem -from plugins.generic.fingerprint import Fingerprint +from plugins.dbms.firebird.enumeration import Enumeration +from plugins.dbms.firebird.filesystem import Filesystem +from plugins.dbms.firebird.fingerprint import Fingerprint +from plugins.dbms.firebird.syntax import Syntax +from plugins.dbms.firebird.takeover import Takeover from plugins.generic.misc import Miscellaneous -from plugins.generic.takeover import Takeover - -class FirebirdMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): +class FirebirdMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines Firebird methods """ @@ -56,224 +40,11 @@ class FirebirdMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover) def __init__(self): self.excludeDbsList = FIREBIRD_SYSTEM_DBS - Enumeration.__init__(self, "Firebird") + Syntax.__init__(self) + Fingerprint.__init__(self) + Enumeration.__init__(self) Filesystem.__init__(self) + Miscellaneous.__init__(self) Takeover.__init__(self) - + unescaper.setUnescape(FirebirdMap.unescape) - - @staticmethod - def unescape(expression, quote=True): - if quote: - while True: - index = expression.find("'") - if index == -1: - break - - firstIndex = index + 1 - index = expression[firstIndex:].find("'") - - if index == -1: - raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression - - lastIndex = firstIndex + index - old = "'%s'" % expression[firstIndex:lastIndex] - unescaped = "" - - for i in range(firstIndex, lastIndex): - unescaped += "ASCII_CHAR(%d)" % (ord(expression[i])) - if i < lastIndex - 1: - unescaped += "||" - - expression = expression.replace(old, unescaped) - else: - unescaped = "".join("ASCII_CHAR(%d)||" % ord(c) for c in expression) - if unescaped[-1] == "||": - unescaped = unescaped[:-1] - - expression = unescaped - - return expression - - @staticmethod - def escape(expression): - while True: - index = expression.find("ASCII_CHAR(") - if index == -1: - break - - firstIndex = index - index = expression[firstIndex:].find(")") - - if index == -1: - raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression - - lastIndex = firstIndex + index + 1 - old = expression[firstIndex:lastIndex] - oldUpper = old.upper() - oldUpper = oldUpper.lstrip("ASCII_CHAR(").rstrip(")") - oldUpper = oldUpper.split("||") - - escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper]) - expression = expression.replace(old, escaped).replace("'||'", "") - - return expression - - def getFingerprint(self): - value = "" - wsOsFp = formatFingerprint("web server", kb.headersFp) - - if wsOsFp: - value += "%s\n" % wsOsFp - - if kb.data.banner: - dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp) - - if dbmsOsFp: - value += "%s\n" % dbmsOsFp - - value += "back-end DBMS: " - - if not conf.extensiveFp: - value += "Firebird" - return value - - actVer = formatDBMSfp() + " (%s)" % (self.__dialectCheck()) - blank = " " * 15 - value += "active fingerprint: %s" % actVer - - if kb.bannerFp: - banVer = kb.bannerFp["dbmsVersion"] - - if re.search("-log$", kb.data.banner): - banVer += ", logging enabled" - - banVer = formatDBMSfp([banVer]) - value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) - - htmlErrorFp = getHtmlErrorFp() - - if htmlErrorFp: - value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) - - return value - - def __sysTablesCheck(self): - retVal = None - table = ( - ("1.0", [" AND EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)"]), - ("1.5", [" AND NULLIF(%d,%d) IS NULL", " AND EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)"]), - ("2.0", [" AND EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", " AND BIT_LENGTH(%d)>0", " AND CHAR_LENGTH(%d)>0"]), - ("2.1", [" AND BIN_XOR(%d,%d)=0", " AND PI()>0.%d", " AND RAND()<1.%d", " AND FLOOR(1.%d)>=0"]) - ) - - for i in xrange(len(table)): - version, checks = table[i] - failed = False - check = checks[randomRange(0,len(checks)-1)].replace("%d", str(randomRange(1,100))) - payload = agent.fullPayload(check) - result = Request.queryPage(payload) - if result: - retVal = version - else: - failed = True - break - if failed: - break - - return retVal - - def __dialectCheck(self): - retVal = None - if kb.dbms: - payload = agent.fullPayload(" AND EXISTS(SELECT CURRENT_DATE FROM RDB$DATABASE)") - result = Request.queryPage(payload) - retVal = "dialect 3" if result else "dialect 1" - return retVal - - def checkDbms(self): - if conf.dbms in FIREBIRD_ALIASES: - setDbms("Firebird") - - self.getBanner() - - if not conf.extensiveFp: - return True - - logMsg = "testing Firebird" - logger.info(logMsg) - - randInt = randomInt() - - payload = agent.fullPayload(" AND EXISTS(SELECT * FROM RDB$DATABASE WHERE %d=%d)" % (randInt, randInt)) - result = Request.queryPage(payload) - - if result: - logMsg = "confirming Firebird" - logger.info(logMsg) - - payload = agent.fullPayload(" AND EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)") - result = Request.queryPage(payload) - - if not result: - warnMsg = "the back-end DMBS is not Firebird" - logger.warn(warnMsg) - - return False - - setDbms("Firebird") - - self.getBanner() - - if not conf.extensiveFp: - return True - - kb.dbmsVersion = [self.__sysTablesCheck()] - - return True - else: - warnMsg = "the back-end DMBS is not Firebird" - logger.warn(warnMsg) - - return False - - def getDbs(self): - warnMsg = "on Firebird it is not possible to enumerate databases" - logger.warn(warnMsg) - - return [] - - def getPasswordHashes(self): - warnMsg = "on Firebird it is not possible to enumerate the user password hashes" - logger.warn(warnMsg) - - return {} - - def readFile(self, rFile): - errMsg = "on Firebird it is not possible to read files" - raise sqlmapUnsupportedFeatureException, errMsg - - def writeFile(self, wFile, dFile, fileType=None, confirm=True): - errMsg = "on Firebird it is not possible to write files" - raise sqlmapUnsupportedFeatureException, errMsg - - def osCmd(self): - errMsg = "on Firebird it is not possible to execute commands" - raise sqlmapUnsupportedFeatureException, errMsg - - def osShell(self): - errMsg = "on Firebird it is not possible to execute commands" - raise sqlmapUnsupportedFeatureException, errMsg - - def osPwn(self): - errMsg = "on Firebird it is not possible to establish an " - errMsg += "out-of-band connection" - raise sqlmapUnsupportedFeatureException, errMsg - - def osSmb(self): - errMsg = "on Firebird it is not possible to establish an " - errMsg += "out-of-band connection" - raise sqlmapUnsupportedFeatureException, errMsg - - def forceDbmsEnum(self): - conf.db = "Firebird" \ No newline at end of file diff --git a/plugins/dbms/firebird/enumeration.py b/plugins/dbms/firebird/enumeration.py new file mode 100644 index 000000000..4462f44cb --- /dev/null +++ b/plugins/dbms/firebird/enumeration.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.data import logger + +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def __init__(self): + GenericEnumeration.__init__(self, "Firebird") + + def getDbs(self): + warnMsg = "on Firebird it is not possible to enumerate databases" + logger.warn(warnMsg) + + return [] + + def getPasswordHashes(self): + warnMsg = "on Firebird it is not possible to enumerate the user password hashes" + logger.warn(warnMsg) + + return {} diff --git a/plugins/dbms/firebird/filesystem.py b/plugins/dbms/firebird/filesystem.py new file mode 100644 index 000000000..2f33b4d63 --- /dev/null +++ b/plugins/dbms/firebird/filesystem.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapUnsupportedFeatureException + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + def __init__(self): + GenericFilesystem.__init__(self) + + def readFile(self, rFile): + errMsg = "on Firebird it is not possible to read files" + raise sqlmapUnsupportedFeatureException, errMsg + + def writeFile(self, wFile, dFile, fileType=None, confirm=True): + errMsg = "on Firebird it is not possible to write files" + raise sqlmapUnsupportedFeatureException, errMsg diff --git a/plugins/dbms/firebird/fingerprint.py b/plugins/dbms/firebird/fingerprint.py new file mode 100644 index 000000000..8091c54e8 --- /dev/null +++ b/plugins/dbms/firebird/fingerprint.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +import re + +from lib.core.agent import agent +from lib.core.common import formatDBMSfp +from lib.core.common import formatFingerprint +from lib.core.common import getHtmlErrorFp +from lib.core.common import randomInt +from lib.core.common import randomRange +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.session import setDbms +from lib.core.settings import FIREBIRD_ALIASES +from lib.request.connect import Connect as Request + +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self) + + def getFingerprint(self): + value = "" + wsOsFp = formatFingerprint("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += "Firebird" + return value + + actVer = formatDBMSfp() + " (%s)" % (self.__dialectCheck()) + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp["dbmsVersion"] + + if re.search("-log$", kb.data.banner): + banVer += ", logging enabled" + + banVer = formatDBMSfp([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = getHtmlErrorFp() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def __sysTablesCheck(self): + retVal = None + table = ( + ("1.0", [" AND EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)"]), + ("1.5", [" AND NULLIF(%d,%d) IS NULL", " AND EXISTS(SELECT CURRENT_TRANSACTION FROM RDB$DATABASE)"]), + ("2.0", [" AND EXISTS(SELECT CURRENT_TIME(0) FROM RDB$DATABASE)", " AND BIT_LENGTH(%d)>0", " AND CHAR_LENGTH(%d)>0"]), + ("2.1", [" AND BIN_XOR(%d,%d)=0", " AND PI()>0.%d", " AND RAND()<1.%d", " AND FLOOR(1.%d)>=0"]) + ) + + for i in xrange(len(table)): + version, checks = table[i] + failed = False + check = checks[randomRange(0,len(checks)-1)].replace("%d", str(randomRange(1,100))) + payload = agent.fullPayload(check) + result = Request.queryPage(payload) + if result: + retVal = version + else: + failed = True + break + if failed: + break + + return retVal + + def __dialectCheck(self): + retVal = None + if kb.dbms: + payload = agent.fullPayload(" AND EXISTS(SELECT CURRENT_DATE FROM RDB$DATABASE)") + result = Request.queryPage(payload) + retVal = "dialect 3" if result else "dialect 1" + return retVal + + def checkDbms(self): + if conf.dbms in FIREBIRD_ALIASES: + setDbms("Firebird") + + self.getBanner() + + if not conf.extensiveFp: + return True + + logMsg = "testing Firebird" + logger.info(logMsg) + + randInt = randomInt() + + payload = agent.fullPayload(" AND EXISTS(SELECT * FROM RDB$DATABASE WHERE %d=%d)" % (randInt, randInt)) + result = Request.queryPage(payload) + + if result: + logMsg = "confirming Firebird" + logger.info(logMsg) + + payload = agent.fullPayload(" AND EXISTS(SELECT CURRENT_USER FROM RDB$DATABASE)") + result = Request.queryPage(payload) + + if not result: + warnMsg = "the back-end DMBS is not Firebird" + logger.warn(warnMsg) + + return False + + setDbms("Firebird") + + self.getBanner() + + if not conf.extensiveFp: + return True + + kb.dbmsVersion = [self.__sysTablesCheck()] + + return True + else: + warnMsg = "the back-end DMBS is not Firebird" + logger.warn(warnMsg) + + return False + + def forceDbmsEnum(self): + conf.db = "Firebird" diff --git a/plugins/dbms/firebird/syntax.py b/plugins/dbms/firebird/syntax.py new file mode 100644 index 000000000..0064b714f --- /dev/null +++ b/plugins/dbms/firebird/syntax.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapSyntaxException + +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + def __init__(self): + GenericSyntax.__init__(self) + + @staticmethod + def unescape(expression, quote=True): + if quote: + while True: + index = expression.find("'") + if index == -1: + break + + firstIndex = index + 1 + index = expression[firstIndex:].find("'") + + if index == -1: + raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression + + lastIndex = firstIndex + index + old = "'%s'" % expression[firstIndex:lastIndex] + unescaped = "" + + for i in range(firstIndex, lastIndex): + unescaped += "ASCII_CHAR(%d)" % (ord(expression[i])) + if i < lastIndex - 1: + unescaped += "||" + + expression = expression.replace(old, unescaped) + else: + unescaped = "".join("ASCII_CHAR(%d)||" % ord(c) for c in expression) + if unescaped[-1] == "||": + unescaped = unescaped[:-1] + + expression = unescaped + + return expression + + @staticmethod + def escape(expression): + while True: + index = expression.find("ASCII_CHAR(") + if index == -1: + break + + firstIndex = index + index = expression[firstIndex:].find(")") + + if index == -1: + raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression + + lastIndex = firstIndex + index + 1 + old = expression[firstIndex:lastIndex] + oldUpper = old.upper() + oldUpper = oldUpper.lstrip("ASCII_CHAR(").rstrip(")") + oldUpper = oldUpper.split("||") + + escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper]) + expression = expression.replace(old, escaped).replace("'||'", "") + + return expression diff --git a/plugins/dbms/firebird/takeover.py b/plugins/dbms/firebird/takeover.py new file mode 100644 index 000000000..e5b49f419 --- /dev/null +++ b/plugins/dbms/firebird/takeover.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapUnsupportedFeatureException + +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + GenericTakeover.__init__(self) + + def osCmd(self): + errMsg = "on Firebird it is not possible to execute commands" + raise sqlmapUnsupportedFeatureException, errMsg + + def osShell(self): + errMsg = "on Firebird it is not possible to execute commands" + raise sqlmapUnsupportedFeatureException, errMsg + + def osPwn(self): + errMsg = "on Firebird it is not possible to establish an " + errMsg += "out-of-band connection" + raise sqlmapUnsupportedFeatureException, errMsg + + def osSmb(self): + errMsg = "on Firebird it is not possible to establish an " + errMsg += "out-of-band connection" + raise sqlmapUnsupportedFeatureException, errMsg diff --git a/plugins/dbms/mssqlserver/syntax.py b/plugins/dbms/mssqlserver/syntax.py index cd4614748..1df8fea1e 100644 --- a/plugins/dbms/mssqlserver/syntax.py +++ b/plugins/dbms/mssqlserver/syntax.py @@ -23,6 +23,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ from lib.core.exception import sqlmapSyntaxException + from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): diff --git a/plugins/dbms/mysql/syntax.py b/plugins/dbms/mysql/syntax.py index f95bbc770..221ffb622 100644 --- a/plugins/dbms/mysql/syntax.py +++ b/plugins/dbms/mysql/syntax.py @@ -23,6 +23,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ from lib.core.exception import sqlmapSyntaxException + from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): diff --git a/plugins/dbms/postgresql/syntax.py b/plugins/dbms/postgresql/syntax.py index ad2304552..b8967f453 100644 --- a/plugins/dbms/postgresql/syntax.py +++ b/plugins/dbms/postgresql/syntax.py @@ -23,6 +23,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ from lib.core.exception import sqlmapSyntaxException + from plugins.generic.syntax import Syntax as GenericSyntax class Syntax(GenericSyntax): diff --git a/plugins/dbms/sqlite/__init__.py b/plugins/dbms/sqlite/__init__.py index 19d3573d3..58578e2f9 100644 --- a/plugins/dbms/sqlite/__init__.py +++ b/plugins/dbms/sqlite/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -$Id: oracle.py 1003 2010-01-02 02:02:12Z inquisb $ +$Id$ This file is part of the sqlmap project, http://sqlmap.sourceforge.net. @@ -22,32 +22,17 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -import re - -from lib.core.agent import agent -from lib.core.common import formatDBMSfp -from lib.core.common import formatFingerprint -from lib.core.common import getHtmlErrorFp -from lib.core.data import conf -from lib.core.data import kb -from lib.core.data import logger -from lib.core.exception import sqlmapSyntaxException -from lib.core.exception import sqlmapUnsupportedFeatureException -from lib.core.session import setDbms -from lib.core.settings import SQLITE_ALIASES from lib.core.settings import SQLITE_SYSTEM_DBS from lib.core.unescaper import unescaper -from lib.request import inject -from lib.request.connect import Connect as Request -from plugins.generic.enumeration import Enumeration -from plugins.generic.filesystem import Filesystem -from plugins.generic.fingerprint import Fingerprint +from plugins.dbms.sqlite.enumeration import Enumeration +from plugins.dbms.sqlite.filesystem import Filesystem +from plugins.dbms.sqlite.fingerprint import Fingerprint +from plugins.dbms.sqlite.syntax import Syntax +from plugins.dbms.sqlite.takeover import Takeover from plugins.generic.misc import Miscellaneous -from plugins.generic.takeover import Takeover - -class SQLiteMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): +class SQLiteMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): """ This class defines SQLite methods """ @@ -55,240 +40,11 @@ class SQLiteMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): def __init__(self): self.excludeDbsList = SQLITE_SYSTEM_DBS - Enumeration.__init__(self, "SQLite") + Syntax.__init__(self) + Fingerprint.__init__(self) + Enumeration.__init__(self) Filesystem.__init__(self) + Miscellaneous.__init__(self) Takeover.__init__(self) - + unescaper.setUnescape(SQLiteMap.unescape) - - @staticmethod - def unescape(expression, quote=True): - # The following is not supported on SQLite 2 - return expression - - if quote: - expression = expression.replace("'", "''") - while True: - index = expression.find("''") - if index == -1: - break - - firstIndex = index + 2 - index = expression[firstIndex:].find("''") - - if index == -1: - raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression.replace("''", "'") - - lastIndex = firstIndex + index - old = "''%s''" % expression[firstIndex:lastIndex] - unescaped = "" - - for i in range(firstIndex, lastIndex): - unescaped += "X'%x'" % ord(expression[i]) - if i < lastIndex - 1: - unescaped += "||" - - #unescaped += ")" - expression = expression.replace(old, unescaped) - expression = expression.replace("''", "'") - else: - expression = "||".join("X'%x" % ord(c) for c in expression) - - return expression - - @staticmethod - def escape(expression): - # Example on SQLite 3, not supported on SQLite 2: - # select X'48'||X'656c6c6f20576f726c6400'; -- Hello World - while True: - index = expression.find("X'") - if index == -1: - break - - firstIndex = index - index = expression[firstIndex+2:].find("'") - - if index == -1: - raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression - - lastIndex = firstIndex + index + 3 - old = expression[firstIndex:lastIndex] - oldUpper = old.upper() - oldUpper = oldUpper.replace("X'", "").replace("'", "") - - for i in xrange(len(oldUpper)/2): - char = oldUpper[i*2:i*2+2] - escaped = "'%s'" % chr(int(char, 16)) - expression = expression.replace(old, escaped) - - return expression - - def getFingerprint(self): - value = "" - wsOsFp = formatFingerprint("web server", kb.headersFp) - - if wsOsFp: - value += "%s\n" % wsOsFp - - if kb.data.banner: - dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp) - - if dbmsOsFp: - value += "%s\n" % dbmsOsFp - - value += "back-end DBMS: " - - if not conf.extensiveFp: - value += "SQLite" - return value - - actVer = formatDBMSfp() - blank = " " * 15 - value += "active fingerprint: %s" % actVer - - if kb.bannerFp: - banVer = kb.bannerFp["dbmsVersion"] - banVer = formatDBMSfp([banVer]) - value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) - - htmlErrorFp = getHtmlErrorFp() - - if htmlErrorFp: - value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) - - return value - - def checkDbms(self): - """ - References for fingerprint: - - * http://www.sqlite.org/lang_corefunc.html - * http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions - """ - - if conf.dbms in SQLITE_ALIASES: - setDbms("SQLite") - - self.getBanner() - - if not conf.extensiveFp: - return True - - logMsg = "testing SQLite" - logger.info(logMsg) - - payload = agent.fullPayload(" AND LAST_INSERT_ROWID()=LAST_INSERT_ROWID()") - result = Request.queryPage(payload) - - if result: - logMsg = "confirming SQLite" - logger.info(logMsg) - - payload = agent.fullPayload(" AND SQLITE_VERSION()=SQLITE_VERSION()") - result = Request.queryPage(payload) - - if not result: - warnMsg = "the back-end DMBS is not SQLite" - logger.warn(warnMsg) - - return False - - setDbms("SQLite") - - self.getBanner() - - if not conf.extensiveFp: - return True - - version = inject.getValue("SUBSTR((SQLITE_VERSION()), 1, 1)", unpack=False, charsetType=2) - kb.dbmsVersion = [ version ] - - return True - else: - warnMsg = "the back-end DMBS is not SQLite" - logger.warn(warnMsg) - - return False - - def forceDbmsEnum(self): - conf.db = "SQLite" - - def getCurrentUser(self): - warnMsg = "on SQLite it is not possible to enumerate the current user" - logger.warn(warnMsg) - - def getCurrentDb(self): - warnMsg = "on SQLite it is not possible to enumerate the current database" - logger.warn(warnMsg) - - def isDba(self): - warnMsg = "on SQLite the current user has all privileges" - logger.warn(warnMsg) - - def getUsers(self): - warnMsg = "on SQLite it is not possible to enumerate the users" - logger.warn(warnMsg) - - return [] - - def getPasswordHashes(self): - warnMsg = "on SQLite it is not possible to enumerate the user password hashes" - logger.warn(warnMsg) - - return {} - - def getPrivileges(self): - warnMsg = "on SQLite it is not possible to enumerate the user privileges" - logger.warn(warnMsg) - - return {} - - def getDbs(self): - warnMsg = "on SQLite it is not possible to enumerate databases" - logger.warn(warnMsg) - - return [] - - def getColumns(self, onlyColNames=False): - errMsg = "on SQLite it is not possible to enumerate database " - errMsg += "table columns" - - if conf.dumpTable or conf.dumpAll: - errMsg += ", provide them with -C option" - raise sqlmapUnsupportedFeatureException, errMsg - - logger.warn(errMsg) - - def dumpColumn(self): - errMsg = "on SQLite you must specify the table and columns to dump" - raise sqlmapUnsupportedFeatureException, errMsg - - def dumpAll(self): - errMsg = "on SQLite you must specify the table and columns to dump" - raise sqlmapUnsupportedFeatureException, errMsg - - def readFile(self, rFile): - errMsg = "on SQLite it is not possible to read files" - raise sqlmapUnsupportedFeatureException, errMsg - - def writeFile(self, wFile, dFile, fileType=None, confirm=True): - errMsg = "on SQLite it is not possible to write files" - raise sqlmapUnsupportedFeatureException, errMsg - - def osCmd(self): - errMsg = "on SQLite it is not possible to execute commands" - raise sqlmapUnsupportedFeatureException, errMsg - - def osShell(self): - errMsg = "on SQLite it is not possible to execute commands" - raise sqlmapUnsupportedFeatureException, errMsg - - def osPwn(self): - errMsg = "on SQLite it is not possible to establish an " - errMsg += "out-of-band connection" - raise sqlmapUnsupportedFeatureException, errMsg - - def osSmb(self): - errMsg = "on SQLite it is not possible to establish an " - errMsg += "out-of-band connection" - raise sqlmapUnsupportedFeatureException, errMsg diff --git a/plugins/dbms/sqlite/enumeration.py b/plugins/dbms/sqlite/enumeration.py new file mode 100644 index 000000000..e9af5cbb3 --- /dev/null +++ b/plugins/dbms/sqlite/enumeration.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import sqlmapUnsupportedFeatureException + +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def __init__(self): + GenericEnumeration.__init__(self, "SQLite") + + def getCurrentUser(self): + warnMsg = "on SQLite it is not possible to enumerate the current user" + logger.warn(warnMsg) + + def getCurrentDb(self): + warnMsg = "on SQLite it is not possible to enumerate the current database" + logger.warn(warnMsg) + + def isDba(self): + warnMsg = "on SQLite the current user has all privileges" + logger.warn(warnMsg) + + def getUsers(self): + warnMsg = "on SQLite it is not possible to enumerate the users" + logger.warn(warnMsg) + + return [] + + def getPasswordHashes(self): + warnMsg = "on SQLite it is not possible to enumerate the user password hashes" + logger.warn(warnMsg) + + return {} + + def getPrivileges(self): + warnMsg = "on SQLite it is not possible to enumerate the user privileges" + logger.warn(warnMsg) + + return {} + + def getDbs(self): + warnMsg = "on SQLite it is not possible to enumerate databases" + logger.warn(warnMsg) + + return [] + + def getColumns(self, onlyColNames=False): + errMsg = "on SQLite it is not possible to enumerate database " + errMsg += "table columns" + + if conf.dumpTable or conf.dumpAll: + errMsg += ", provide them with -C option" + raise sqlmapUnsupportedFeatureException, errMsg + + logger.warn(errMsg) + + def dumpColumn(self): + errMsg = "on SQLite you must specify the table and columns to dump" + raise sqlmapUnsupportedFeatureException, errMsg + + def dumpAll(self): + errMsg = "on SQLite you must specify the table and columns to dump" + raise sqlmapUnsupportedFeatureException, errMsg diff --git a/plugins/dbms/sqlite/filesystem.py b/plugins/dbms/sqlite/filesystem.py new file mode 100644 index 000000000..607c28023 --- /dev/null +++ b/plugins/dbms/sqlite/filesystem.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapUnsupportedFeatureException + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + def __init__(self): + GenericFilesystem.__init__(self) + + def readFile(self, rFile): + errMsg = "on SQLite it is not possible to read files" + raise sqlmapUnsupportedFeatureException, errMsg + + def writeFile(self, wFile, dFile, fileType=None, confirm=True): + errMsg = "on SQLite it is not possible to write files" + raise sqlmapUnsupportedFeatureException, errMsg diff --git a/plugins/dbms/sqlite/fingerprint.py b/plugins/dbms/sqlite/fingerprint.py new file mode 100644 index 000000000..2839d6b06 --- /dev/null +++ b/plugins/dbms/sqlite/fingerprint.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.agent import agent +from lib.core.common import formatDBMSfp +from lib.core.common import formatFingerprint +from lib.core.common import getHtmlErrorFp +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.session import setDbms +from lib.core.settings import SQLITE_ALIASES +from lib.request import inject +from lib.request.connect import Connect as Request + +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self) + + def getFingerprint(self): + value = "" + wsOsFp = formatFingerprint("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += "SQLite" + return value + + actVer = formatDBMSfp() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp["dbmsVersion"] + banVer = formatDBMSfp([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = getHtmlErrorFp() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + """ + References for fingerprint: + + * http://www.sqlite.org/lang_corefunc.html + * http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions + """ + + if conf.dbms in SQLITE_ALIASES: + setDbms("SQLite") + + self.getBanner() + + if not conf.extensiveFp: + return True + + logMsg = "testing SQLite" + logger.info(logMsg) + + payload = agent.fullPayload(" AND LAST_INSERT_ROWID()=LAST_INSERT_ROWID()") + result = Request.queryPage(payload) + + if result: + logMsg = "confirming SQLite" + logger.info(logMsg) + + payload = agent.fullPayload(" AND SQLITE_VERSION()=SQLITE_VERSION()") + result = Request.queryPage(payload) + + if not result: + warnMsg = "the back-end DMBS is not SQLite" + logger.warn(warnMsg) + + return False + + setDbms("SQLite") + + self.getBanner() + + if not conf.extensiveFp: + return True + + version = inject.getValue("SUBSTR((SQLITE_VERSION()), 1, 1)", unpack=False, charsetType=2) + kb.dbmsVersion = [ version ] + + return True + else: + warnMsg = "the back-end DMBS is not SQLite" + logger.warn(warnMsg) + + return False + + def forceDbmsEnum(self): + conf.db = "SQLite" diff --git a/plugins/dbms/sqlite/syntax.py b/plugins/dbms/sqlite/syntax.py new file mode 100644 index 000000000..cb6f4f556 --- /dev/null +++ b/plugins/dbms/sqlite/syntax.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapSyntaxException + +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + def __init__(self): + GenericSyntax.__init__(self) + + @staticmethod + def unescape(expression, quote=True): + # The following is not supported on SQLite 2 + return expression + + if quote: + expression = expression.replace("'", "''") + while True: + index = expression.find("''") + if index == -1: + break + + firstIndex = index + 2 + index = expression[firstIndex:].find("''") + + if index == -1: + raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression.replace("''", "'") + + lastIndex = firstIndex + index + old = "''%s''" % expression[firstIndex:lastIndex] + unescaped = "" + + for i in range(firstIndex, lastIndex): + unescaped += "X'%x'" % ord(expression[i]) + if i < lastIndex - 1: + unescaped += "||" + + #unescaped += ")" + expression = expression.replace(old, unescaped) + expression = expression.replace("''", "'") + else: + expression = "||".join("X'%x" % ord(c) for c in expression) + + return expression + + @staticmethod + def escape(expression): + # Example on SQLite 3, not supported on SQLite 2: + # select X'48'||X'656c6c6f20576f726c6400'; -- Hello World + while True: + index = expression.find("X'") + if index == -1: + break + + firstIndex = index + index = expression[firstIndex+2:].find("'") + + if index == -1: + raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression + + lastIndex = firstIndex + index + 3 + old = expression[firstIndex:lastIndex] + oldUpper = old.upper() + oldUpper = oldUpper.replace("X'", "").replace("'", "") + + for i in xrange(len(oldUpper)/2): + char = oldUpper[i*2:i*2+2] + escaped = "'%s'" % chr(int(char, 16)) + expression = expression.replace(old, escaped) + + return expression diff --git a/plugins/dbms/sqlite/takeover.py b/plugins/dbms/sqlite/takeover.py new file mode 100644 index 000000000..eb79d49fd --- /dev/null +++ b/plugins/dbms/sqlite/takeover.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +$Id$ + +This file is part of the sqlmap project, http://sqlmap.sourceforge.net. + +Copyright (c) 2007-2010 Bernardo Damele A. G. +Copyright (c) 2006 Daniele Bellucci + +sqlmap is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation version 2 of the License. + +sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with sqlmap; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" + +from lib.core.exception import sqlmapUnsupportedFeatureException + +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + GenericTakeover.__init__(self) + + def osCmd(self): + errMsg = "on SQLite it is not possible to execute commands" + raise sqlmapUnsupportedFeatureException, errMsg + + def osShell(self): + errMsg = "on SQLite it is not possible to execute commands" + raise sqlmapUnsupportedFeatureException, errMsg + + def osPwn(self): + errMsg = "on SQLite it is not possible to establish an " + errMsg += "out-of-band connection" + raise sqlmapUnsupportedFeatureException, errMsg + + def osSmb(self): + errMsg = "on SQLite it is not possible to establish an " + errMsg += "out-of-band connection" + raise sqlmapUnsupportedFeatureException, errMsg