diff --git a/lib/controller/handler.py b/lib/controller/handler.py
index 7b21df61b..c70397df1 100644
--- a/lib/controller/handler.py
+++ b/lib/controller/handler.py
@@ -23,6 +23,7 @@ from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import SYBASE_ALIASES
+from lib.core.settings import DB2_ALIASES
from plugins.dbms.mssqlserver import MSSQLServerMap
from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn
@@ -42,6 +43,8 @@ from plugins.dbms.maxdb import MaxDBMap
from plugins.dbms.maxdb.connector import Connector as MaxDBConn
from plugins.dbms.sybase import SybaseMap
from plugins.dbms.sybase.connector import Connector as SybaseConn
+from plugins.dbms.db2 import DB2Map
+from plugins.dbms.db2.connector import Connector as DB2Conn
def setHandler():
"""
@@ -50,7 +53,7 @@ def setHandler():
"""
count = 0
- dbmsNames = ( "MySQL", "Oracle", "PostgreSQL", "Microsoft SQL Server", "SQLite", "Microsoft Access", "Firebird", "SAP MaxDB", "Sybase" )
+ dbmsNames = ( "MySQL", "Oracle", "PostgreSQL", "Microsoft SQL Server", "SQLite", "Microsoft Access", "Firebird", "SAP MaxDB", "Sybase", "DB2" )
dbmsObj = [
( MYSQL_ALIASES, MySQLMap, MySQLConn ),
( ORACLE_ALIASES, OracleMap, OracleConn ),
@@ -61,6 +64,7 @@ def setHandler():
( FIREBIRD_ALIASES, FirebirdMap, FirebirdConn ),
( MAXDB_ALIASES, MaxDBMap, MaxDBConn ),
( SYBASE_ALIASES, SybaseMap, SybaseConn ),
+ ( DB2_ALIASES, DB2Map, DB2Conn )
]
if Backend.getIdentifiedDbms() is not None:
diff --git a/lib/core/agent.py b/lib/core/agent.py
index 143657685..253f73adf 100644
--- a/lib/core/agent.py
+++ b/lib/core/agent.py
@@ -407,7 +407,7 @@ class Agent:
if Backend.isDbms(DBMS.MYSQL):
concatenatedQuery = "CONCAT(%s,%s)" % (query1, query2)
- elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE):
+ elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2):
concatenatedQuery = "%s||%s" % (query1, query2)
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
@@ -466,7 +466,7 @@ class Agent:
elif fieldsNoSelect:
concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.misc.start, concatenatedQuery, kb.misc.stop)
- elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE):
+ elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2):
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1)
concatenatedQuery += "||'%s'" % kb.misc.stop
@@ -643,7 +643,7 @@ class Agent:
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num+1, num+1)
limitedQuery += " %s" % limitStr
- elif Backend.isDbms(DBMS.ORACLE):
+ elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
if " ORDER BY " in limitedQuery and "(SELECT " in limitedQuery:
orderBy = limitedQuery[limitedQuery.index(" ORDER BY "):]
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
diff --git a/lib/core/common.py b/lib/core/common.py
index 61453bd53..44aa1e21a 100644
--- a/lib/core/common.py
+++ b/lib/core/common.py
@@ -2546,7 +2546,7 @@ def safeSQLIdentificatorNaming(name, isTable=False):
if not re.match(r"\A[A-Za-z0-9_]+\Z", parts[i]):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS):
parts[i] = "`%s`" % parts[i].strip("`")
- elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.PGSQL):
+ elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.DB2):
parts[i] = "\"%s\"" % parts[i].strip("\"")
retVal = ".".join(parts)
@@ -2563,7 +2563,7 @@ def unsafeSQLIdentificatorNaming(name):
if isinstance(name, basestring):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS):
retVal = name.replace("`", "")
- elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.PGSQL):
+ elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.PGSQL, DBMS.DB2):
retVal = name.replace("\"", "")
if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
prefix = "%s." % DEFAULT_MSSQL_SCHEMA
diff --git a/lib/core/data.py b/lib/core/data.py
index 716948a23..110b97f26 100644
--- a/lib/core/data.py
+++ b/lib/core/data.py
@@ -19,6 +19,7 @@ from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import SYBASE_ALIASES
+from lib.core.settings import DB2_ALIASES
# sqlmap paths
paths = advancedDict()
diff --git a/lib/core/dicts.py b/lib/core/dicts.py
index 4582911f0..3aee461b4 100644
--- a/lib/core/dicts.py
+++ b/lib/core/dicts.py
@@ -98,3 +98,14 @@ firebirdPrivs = {
"R": "REFERENCES",
"E": "EXECUTE"
}
+
+db2Privs = {
+ 1:"CONTROLAUTH",
+ 2:"ALTERAUTH",
+ 3:"DELETEAUTH",
+ 4:"INDEXAUTH",
+ 5:"INSERTAUTH",
+ 6:"REFAUTH",
+ 7:"SELECTAUTH",
+ 8:"UPDATEAUTH"
+ }
\ No newline at end of file
diff --git a/lib/core/enums.py b/lib/core/enums.py
index f0366b5a4..6cae3e396 100644
--- a/lib/core/enums.py
+++ b/lib/core/enums.py
@@ -34,6 +34,7 @@ class DBMS:
PGSQL = "PostgreSQL"
SQLITE = "SQLite"
SYBASE = "Sybase"
+ DB2 = "IBM DB2"
class OS:
LINUX = "Linux"
diff --git a/lib/core/option.py b/lib/core/option.py
index 7034fc671..0dfba201f 100644
--- a/lib/core/option.py
+++ b/lib/core/option.py
@@ -89,6 +89,7 @@ from lib.core.settings import ACCESS_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import MAXDB_ALIASES
from lib.core.settings import SYBASE_ALIASES
+from lib.core.settings import DB2_ALIASES
from lib.core.settings import BURP_SPLITTER
from lib.core.settings import MAX_NUMBER_OF_THREADS
from lib.core.settings import TIME_DEFAULT_DELAY
@@ -682,7 +683,7 @@ def __setDBMS():
for aliases in (MSSQL_ALIASES, MYSQL_ALIASES, PGSQL_ALIASES, \
ORACLE_ALIASES, SQLITE_ALIASES, ACCESS_ALIASES, \
- FIREBIRD_ALIASES, MAXDB_ALIASES, SYBASE_ALIASES):
+ FIREBIRD_ALIASES, MAXDB_ALIASES, SYBASE_ALIASES, DB2_ALIASES):
if conf.dbms in aliases:
conf.dbms = aliases[0]
diff --git a/lib/core/settings.py b/lib/core/settings.py
index 24eba1c2e..bb6a5c5e0 100644
--- a/lib/core/settings.py
+++ b/lib/core/settings.py
@@ -147,6 +147,8 @@ FIREBIRD_SYSTEM_DBS = ( "RDB$BACKUP_HISTORY", "RDB$CHARACTER_SETS", "RDB$CHECK_C
"RDB$TRIGGER_MESSAGES", "RDB$TYPES", "RDB$USER_PRIVILEGES", "RDB$VIEW_RELATIONS" )
MAXDB_SYSTEM_DBS = ( "SYSINFO", "DOMAIN" )
SYBASE_SYSTEM_DBS = ( "master", "model", "sybsystemdb", "sybsystemprocs" )
+DB2_SYSTEM_DBS = ( "NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS", "SYSPROC", "SYSPUBLIC",\
+ "SYSSTAT", "SYSTOOLS" )
MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ]
MYSQL_ALIASES = [ "mysql", "my" ]
@@ -157,8 +159,9 @@ ACCESS_ALIASES = [ "access", "jet", "microsoft access", "msaccess" ]
FIREBIRD_ALIASES = [ "firebird", "mozilla firebird", "interbase", "ibase", "fb" ]
MAXDB_ALIASES = [ "maxdb", "sap maxdb", "sap db" ]
SYBASE_ALIASES = [ "sybase", "sybase sql server" ]
+DB2_ALIASES = [ "ibm db2", "db2" ]
-SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES
+SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES
SUPPORTED_OS = ( "linux", "windows" )
DBMS_DICT = { DBMS.MSSQL: [MSSQL_ALIASES, "python-pymssql", "http://pymssql.sourceforge.net/"],
@@ -169,7 +172,8 @@ DBMS_DICT = { DBMS.MSSQL: [MSSQL_ALIASES, "python-pymssql", "http://pymssql.sour
DBMS.ACCESS: [ACCESS_ALIASES, "python-pyodbc", "http://pyodbc.googlecode.com/"],
DBMS.FIREBIRD: [FIREBIRD_ALIASES, "python-kinterbasdb", "http://kinterbasdb.sourceforge.net/"],
DBMS.MAXDB: [MAXDB_ALIASES, None, None],
- DBMS.SYBASE: [SYBASE_ALIASES, "python-pymssql", "http://pymssql.sourceforge.net/"]
+ DBMS.SYBASE: [SYBASE_ALIASES, "python-pymssql", "http://pymssql.sourceforge.net/"],
+ DBMS.DB2: [DB2_ALIASES, None, None]
}
REFERER_ALIASES = ( "ref", "referer", "referrer" )
diff --git a/plugins/dbms/db2/__init__.py b/plugins/dbms/db2/__init__.py
new file mode 100644
index 000000000..2dbbf0540
--- /dev/null
+++ b/plugins/dbms/db2/__init__.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+"""
+$Id: __init__.py 3678 2011-04-15 12:33:18Z stamparm $
+
+Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+from lib.core.enums import DBMS
+from lib.core.settings import DB2_SYSTEM_DBS
+from lib.core.unescaper import unescaper
+
+from plugins.dbms.db2.enumeration import Enumeration
+from plugins.dbms.db2.filesystem import Filesystem
+from plugins.dbms.db2.fingerprint import Fingerprint
+from plugins.dbms.db2.syntax import Syntax
+from plugins.dbms.db2.takeover import Takeover
+from plugins.generic.misc import Miscellaneous
+
+class DB2Map(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
+ """
+ This class defines DB2 methods
+ """
+
+ def __init__(self):
+ self.excludeDbsList = DB2_SYSTEM_DBS
+
+ Syntax.__init__(self)
+ Fingerprint.__init__(self)
+ Enumeration.__init__(self)
+ Filesystem.__init__(self)
+ Miscellaneous.__init__(self)
+ Takeover.__init__(self)
+
+ unescaper[DBMS.DB2] = Syntax.unescape
diff --git a/plugins/dbms/db2/connector.py b/plugins/dbms/db2/connector.py
new file mode 100644
index 000000000..8e51ce880
--- /dev/null
+++ b/plugins/dbms/db2/connector.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+"""
+$Id: connector.py 3678 2011-04-15 12:33:18Z stamparm $
+
+Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+try:
+ import pyodbc
+except ImportError, _:
+ pass
+
+from lib.core.data import logger
+from lib.core.exception import sqlmapConnectionException
+from lib.core.exception import sqlmapUnsupportedFeatureException
+
+from plugins.generic.connector import Connector as GenericConnector
+
+class Connector(GenericConnector):
+ """
+ Homepage: http://pyodbc.googlecode.com/
+ User guide: http://code.google.com/p/pyodbc/wiki/GettingStarted
+ API: http://code.google.com/p/pyodbc/w/list
+ Debian package: python-pyodbc
+ License: MIT
+ """
+
+ def __init__(self):
+ GenericConnector.__init__(self)
\ No newline at end of file
diff --git a/plugins/dbms/db2/enumeration.py b/plugins/dbms/db2/enumeration.py
new file mode 100644
index 000000000..0a44f7c04
--- /dev/null
+++ b/plugins/dbms/db2/enumeration.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+"""
+$Id: enumeration.py 3678 2011-04-15 12:33:18Z stamparm $
+
+Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+
+from lib.core.data import logger
+from plugins.generic.enumeration import Enumeration as GenericEnumeration
+
+class Enumeration(GenericEnumeration):
+ def __init__(self):
+ GenericEnumeration.__init__(self)
+
+ def getPasswordHashes(self):
+ warnMsg = "on DB2 it is not possible to list password hashes"
+ logger.warn(warnMsg)
+
+ return {}
\ No newline at end of file
diff --git a/plugins/dbms/db2/filesystem.py b/plugins/dbms/db2/filesystem.py
new file mode 100644
index 000000000..f140d0ab4
--- /dev/null
+++ b/plugins/dbms/db2/filesystem.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+"""
+$Id: filesystem.py 3678 2011-04-15 12:33:18Z stamparm $
+
+Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+from lib.core.common import randomStr
+from lib.core.data import conf
+from lib.core.data import kb
+from lib.core.data import logger
+from lib.core.enums import PLACE
+from lib.core.exception import sqlmapNoneDataException
+from lib.request import inject
+from lib.techniques.inband.union.use import unionUse
+
+from plugins.generic.filesystem import Filesystem as GenericFilesystem
+
+class Filesystem(GenericFilesystem):
+ def __init__(self):
+ GenericFilesystem.__init__(self)
diff --git a/plugins/dbms/db2/fingerprint.py b/plugins/dbms/db2/fingerprint.py
new file mode 100644
index 000000000..3ad3335fd
--- /dev/null
+++ b/plugins/dbms/db2/fingerprint.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+
+"""
+$Id: fingerprint.py 3678 2011-04-15 12:33:18Z stamparm $
+
+Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+
+from lib.core.common import Backend
+from lib.core.common import Format
+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.enums import DBMS
+from lib.core.session import setDbms
+from lib.core.settings import DB2_ALIASES
+from lib.request import inject
+
+from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
+
+class Fingerprint(GenericFingerprint):
+ def __init__(self):
+ GenericFingerprint.__init__(self, DBMS.DB2)
+
+ def versionCheck(self):
+ minor, major = None, None
+
+ for version in reversed(xrange(5, 15)):
+ result = inject.checkBooleanExpression("(SELECT COUNT(*) FROM sysibm.sysversions WHERE versionnumber BETWEEN %d000000 AND %d999999)>0" % (version, version))
+ if result:
+ major = version
+
+ for version in reversed(xrange(0, 20)):
+ result = inject.checkBooleanExpression("(SELECT COUNT(*) FROM sysibm.sysversions WHERE versionnumber BETWEEN %d%02d0000 AND %d%02d9999)>0" % (major, version, major, version))
+ if result:
+ minor = version
+ version = "%s.%s" % (major, minor)
+ break
+ break
+
+ if major and minor:
+ return "%s.%s" % (major, minor)
+ else:
+ return None
+
+ def getFingerprint(self):
+ value = ""
+ wsOsFp = Format.getOs("web server", kb.headersFp)
+
+ if wsOsFp:
+ value += "%s\n" % wsOsFp
+
+ if kb.data.banner:
+ dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp)
+
+ if dbmsOsFp:
+ value += "%s\n" % dbmsOsFp
+
+ value += "back-end DBMS: "
+
+ if not conf.extensiveFp:
+ value += DBMS.DB2
+ return value
+
+ actVer = Format.getDbms()
+ blank = " " * 15
+ value += "active fingerprint: %s" % actVer
+
+ if kb.bannerFp:
+ banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None
+ banVer = Format.getDbms([banVer])
+ value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
+
+ htmlErrorFp = Format.getErrorParsedDBMSes()
+
+ if htmlErrorFp:
+ value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
+
+ return value
+
+ def checkDbms(self):
+ if not conf.extensiveFp and (Backend.isDbmsWithin(DB2_ALIASES) or conf.dbms in DB2_ALIASES):
+ setDbms(DBMS.DB2)
+
+ return True
+
+ logMsg = "testing %s" % DBMS.DB2
+ logger.info(logMsg)
+
+ randInt = randomInt()
+ result = inject.checkBooleanExpression("(SELECT %d FROM sysibm.sysdummy1) = %d" % (randInt, randInt))
+
+ if result:
+ logMsg = "confirming %s" % DBMS.DB2
+ logger.info(logMsg)
+
+ version = self.versionCheck()
+
+ if version:
+ Backend.setVersion(version)
+ setDbms("%s %s" % (DBMS.DB2, Backend.getVersion()))
+ else:
+ setDbms(DBMS.DB2)
+
+
+ return True
+ else:
+ warnMsg = "the back-end DBMS is not %s" % DBMS.DB2
+ logger.warn(warnMsg)
+
+ return False
\ No newline at end of file
diff --git a/plugins/dbms/db2/syntax.py b/plugins/dbms/db2/syntax.py
new file mode 100644
index 000000000..517347741
--- /dev/null
+++ b/plugins/dbms/db2/syntax.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+"""
+$Id: syntax.py 3678 2011-04-15 12:33:18Z stamparm $
+
+Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+from lib.core.data import logger
+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:
+ expression = "||".join("CHR(%d)" % ord(c) for c in expression)
+
+ return expression
+
+ @staticmethod
+ def escape(expression):
+ logMsg = "escaping %s" % expression
+ logger.info(logMsg)
+ 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)
+
+ return expression
diff --git a/plugins/dbms/db2/takeover.py b/plugins/dbms/db2/takeover.py
new file mode 100644
index 000000000..041b0ee40
--- /dev/null
+++ b/plugins/dbms/db2/takeover.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+"""
+$Id: takeover.py 3678 2011-04-15 12:33:18Z stamparm $
+
+Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.agent import agent
+from lib.core.common import isTechniqueAvailable
+from lib.core.common import normalizePath
+from lib.core.common import ntToPosixSlashes
+from lib.core.common import randomStr
+from lib.core.common import readInput
+from lib.core.data import kb
+from lib.core.data import logger
+from lib.core.data import paths
+from lib.core.enums import PAYLOAD
+from lib.request import inject
+from lib.request.connect import Connect as Request
+
+from plugins.generic.takeover import Takeover as GenericTakeover
+
+class Takeover(GenericTakeover):
+ def __init__(self):
+ self.__basedir = None
+ self.__datadir = None
+
+ GenericTakeover.__init__(self)
\ No newline at end of file
diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py
index 118ddff0e..9fa41dd6e 100644
--- a/plugins/generic/enumeration.py
+++ b/plugins/generic/enumeration.py
@@ -43,6 +43,7 @@ from lib.core.dicts import firebirdTypes
from lib.core.dicts import mysqlPrivs
from lib.core.dicts import pgsqlPrivs
from lib.core.dicts import firebirdPrivs
+from lib.core.dicts import db2Privs
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import PAYLOAD
@@ -98,8 +99,14 @@ class Enumeration:
infoMsg = "fetching banner"
logger.info(infoMsg)
- query = queries[Backend.getIdentifiedDbms()].banner.query
- kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=False))
+ # Needed for DB2 versions < 9
+ if Backend.isDbms(DBMS.DB2) and int(Backend.getVersion().split(".")[0]) < 9:
+ query = queries[Backend.getIdentifiedDbms()].banner.query2
+ kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=False))
+ else:
+ query = queries[Backend.getIdentifiedDbms()].banner.query
+ kb.data.banner = unArrayizeValue(inject.getValue(query, safeCharEncode=False))
+
bannerParser(kb.data.banner)
if conf.os and conf.os == "windows":
@@ -191,7 +198,7 @@ class Enumeration:
errMsg = "unable to retrieve the number of database users"
raise sqlmapNoneDataException, errMsg
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
plusOne = True
else:
plusOne = False
@@ -419,7 +426,7 @@ class Enumeration:
logger.info(infoMsg)
- if conf.user and Backend.isDbms(DBMS.ORACLE):
+ if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
conf.user = conf.user.upper()
if conf.user:
@@ -559,7 +566,7 @@ class Enumeration:
privileges = set()
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
plusOne = True
else:
plusOne = False
@@ -617,6 +624,25 @@ class Enumeration:
elif Backend.isDbms(DBMS.FIREBIRD):
privileges.add(firebirdPrivs[privilege.strip()])
+ # In DB2 we get Y or G if the privilege is
+ # True, N otherwise
+ elif Backend.isDbms(DBMS.DB2):
+ privs = privilege.split(",")
+ privilege = privs[0]
+ privs = privs[1]
+ privs = list(privs.strip())
+ i = 1
+
+ for priv in privs:
+ if priv.upper() in ("Y", "G"):
+ for position, db2Priv in db2Privs.items():
+ if position == i:
+ privilege += ", " + db2Priv
+
+ i += 1
+
+ privileges.add(privilege)
+
if self.__isAdminFromPrivileges(privileges):
areAdmins.add(user)
@@ -665,6 +691,12 @@ class Enumeration:
warnMsg += "names on other DBMSes"
logger.warn(warnMsg)
+ if Backend.isDbms(DBMS.DB2):
+ warnMsg = "schema names are going to be used on DB2 "
+ warnMsg += "for enumeration as the counterpart to database "
+ warnMsg += "names on other DBMSes"
+ logger.warn(warnMsg)
+
infoMsg = "fetching database (schema) names"
else:
infoMsg = "fetching database names"
@@ -697,7 +729,7 @@ class Enumeration:
errMsg = "unable to retrieve the number of databases"
logger.error(errMsg)
else:
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
plusOne = True
else:
plusOne = False
@@ -758,7 +790,7 @@ class Enumeration:
if conf.db == "CD":
conf.db = self.getCurrentDb()
- if conf.db and Backend.isDbms(DBMS.ORACLE):
+ if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
conf.db = conf.db.upper()
if conf.db:
@@ -870,7 +902,7 @@ class Enumeration:
tables = []
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
plusOne = True
else:
plusOne = False
@@ -914,10 +946,14 @@ class Enumeration:
warnMsg += "table(s) columns"
logger.warn(warnMsg)
- conf.db = self.getCurrentDb()
+ # In DB2 we use the current user as default schema (db)
+ if Backend.isDbms(DBMS.DB2):
+ conf.db = self.getCurrentUser()
+ else:
+ conf.db = self.getCurrentDb()
elif conf.db is not None:
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
conf.db = conf.db.upper()
if ',' in conf.db:
@@ -928,7 +964,7 @@ class Enumeration:
conf.db = safeSQLIdentificatorNaming(conf.db)
if conf.col:
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
conf.col = conf.col.upper()
colList = conf.col.split(",")
@@ -939,7 +975,7 @@ class Enumeration:
colList[colList.index(col)] = safeSQLIdentificatorNaming(col)
if conf.tbl:
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
conf.tbl = conf.tbl.upper()
tblList = conf.tbl.split(",")
@@ -1105,7 +1141,7 @@ class Enumeration:
query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
query += condQuery
- elif Backend.isDbms(DBMS.ORACLE):
+ elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.blind.count % unsafeSQLIdentificatorNaming(tbl.upper())
query += condQuery
@@ -1144,7 +1180,7 @@ class Enumeration:
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
query += condQuery
field = None
- elif Backend.isDbms(DBMS.ORACLE):
+ elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.blind.query % unsafeSQLIdentificatorNaming(tbl.upper())
query += condQuery
field = None
@@ -1166,7 +1202,7 @@ class Enumeration:
if not onlyColNames:
if Backend.getIdentifiedDbms() in ( DBMS.MYSQL, DBMS.PGSQL ):
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db))
- elif Backend.isDbms(DBMS.ORACLE):
+ elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column)
elif Backend.isDbms(DBMS.MSSQL):
query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db,
@@ -1266,7 +1302,11 @@ class Enumeration:
warnMsg += "number of entries for table '%s'" % conf.tbl
logger.warn(warnMsg)
- conf.db = self.getCurrentDb()
+ # In DB2 we use the current user as default schema (db)
+ if Backend.isDbms(DBMS.DB2):
+ conf.db = self.getCurrentUser()
+ else:
+ conf.db = self.getCurrentDb()
self.forceDbmsEnum()
@@ -1419,7 +1459,11 @@ class Enumeration:
warnMsg += "'%s' entries" % conf.tbl
logger.warn(warnMsg)
- conf.db = self.getCurrentDb()
+ # In DB2 we use the current user as default schema (db)
+ if Backend.isDbms(DBMS.DB2):
+ conf.db = self.getCurrentUser()
+ else:
+ conf.db = self.getCurrentDb()
rootQuery = queries[Backend.getIdentifiedDbms()].dump_table
@@ -1541,7 +1585,7 @@ class Enumeration:
infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg)
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.blind.count % (conf.tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), conf.tbl.upper())))
elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD):
query = rootQuery.blind.count % conf.tbl
@@ -1581,7 +1625,7 @@ class Enumeration:
entries, lengths = retVal
else:
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
plusOne = True
else:
plusOne = False
@@ -1598,7 +1642,7 @@ class Enumeration:
if Backend.getIdentifiedDbms() in ( DBMS.MYSQL, DBMS.PGSQL ):
query = rootQuery.blind.query % (column, conf.db,
conf.tbl, index)
- elif Backend.isDbms(DBMS.ORACLE):
+ elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.blind.query % (column, column,
conf.tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), conf.tbl.upper())),
index)
@@ -1774,6 +1818,9 @@ class Enumeration:
for db in dbList:
db = safeSQLIdentificatorNaming(db)
+ if Backend.isDbms(DBMS.DB2):
+ db = db.upper()
+
infoMsg = "searching database"
if dbConsider == "1":
infoMsg += "s like"
@@ -1839,6 +1886,8 @@ class Enumeration:
query = rootQuery.blind.query
query += dbQuery
query += exclDbsQuery
+ if Backend.isDbms(DBMS.DB2):
+ query += ") AS foobar"
query = agent.limitQuery(index, query, dbCond)
value = inject.getValue(query, inband=False, error=False)
@@ -1884,7 +1933,7 @@ class Enumeration:
for tbl in tblList:
tbl = safeSQLIdentificatorNaming(tbl, True)
- if Backend.isDbms(DBMS.ORACLE):
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
tbl = tbl.upper()
infoMsg = "searching table"
@@ -1951,6 +2000,8 @@ class Enumeration:
query = rootQuery.blind.query
query += tblQuery
query += exclDbsQuery
+ if Backend.getIdentifiedDbms() == DBMS.DB2:
+ query += ") AS foobar"
query = agent.limitQuery(index, query)
foundDb = inject.getValue(query, inband=False, error=False)
foundDb = safeSQLIdentificatorNaming(foundDb)
@@ -2048,6 +2099,9 @@ class Enumeration:
for column in colList:
column = safeSQLIdentificatorNaming(column)
+ if Backend.isDbms(DBMS.DB2):
+ column = column.upper()
+
infoMsg = "searching column"
if colConsider == "1":
infoMsg += "s like"
@@ -2132,6 +2186,8 @@ class Enumeration:
query = rootQuery.blind.query
query += colQuery
query += exclDbsQuery
+ if Backend.isDbms(DBMS.DB2):
+ query += ") AS foobar"
query = agent.limitQuery(index, query)
db = inject.getValue(query, inband=False, error=False)
db = safeSQLIdentificatorNaming(db)
diff --git a/xml/queries.xml b/xml/queries.xml
index 0ebb846ca..993585e4b 100644
--- a/xml/queries.xml
+++ b/xml/queries.xml
@@ -540,4 +540,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+