Added support to connect directly also to Oracle - see #158

This commit is contained in:
Bernardo Damele 2010-03-27 21:50:19 +00:00
parent 1416cd0d86
commit a0290a257b
7 changed files with 98 additions and 12 deletions

View File

@ -628,7 +628,7 @@ def parseTargetDirect():
dbmsDict = { "Microsoft SQL Server": [MSSQL_ALIASES, "python-pymssql", "http://pymssql.sourceforge.net/"], dbmsDict = { "Microsoft SQL Server": [MSSQL_ALIASES, "python-pymssql", "http://pymssql.sourceforge.net/"],
"MySQL": [MYSQL_ALIASES, "python-mysqldb", "http://mysql-python.sourceforge.net/"], "MySQL": [MYSQL_ALIASES, "python-mysqldb", "http://mysql-python.sourceforge.net/"],
"PostgreSQL": [PGSQL_ALIASES, "python-psycopg2", "http://initd.org/psycopg/"], "PostgreSQL": [PGSQL_ALIASES, "python-psycopg2", "http://initd.org/psycopg/"],
"Oracle": [ORACLE_ALIASES, "", ""], "Oracle": [ORACLE_ALIASES, "python cx_Oracle", "http://cx-oracle.sourceforge.net/"],
"SQLite": [SQLITE_ALIASES, "", ""], "SQLite": [SQLITE_ALIASES, "", ""],
"Access": [ACCESS_ALIASES, "", ""], "Access": [ACCESS_ALIASES, "", ""],
"Firebird": [FIREBIRD_ALIASES, "", ""] } "Firebird": [FIREBIRD_ALIASES, "", ""] }
@ -642,6 +642,8 @@ def parseTargetDirect():
import MySQLdb import MySQLdb
elif dbmsName == "PostgreSQL": elif dbmsName == "PostgreSQL":
import psycopg2 import psycopg2
elif dbmsName == "Oracle":
import cx_Oracle
except ImportError, _: except ImportError, _:
errMsg = "sqlmap requires %s third-party library " % data[1] errMsg = "sqlmap requires %s third-party library " % data[1]
errMsg += "in order to directly connect to the database " errMsg += "in order to directly connect to the database "

View File

@ -268,6 +268,9 @@ class Connect:
values = None values = None
select = False select = False
if kb.dbms == "Oracle" and value.startswith("SELECT ") and " FROM " not in value:
value = "%s FROM DUAL" % value
for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
for sqlStatement in sqlStatements: for sqlStatement in sqlStatements:
if value.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement": if value.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement":

View File

@ -356,6 +356,9 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None,
values = None values = None
select = False select = False
if kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
expression = "%s FROM DUAL" % expression
for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
for sqlStatement in sqlStatements: for sqlStatement in sqlStatements:
if expression.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement": if expression.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement":
@ -419,6 +422,9 @@ def goStacked(expression, silent=False):
values = None values = None
select = False select = False
if kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
expression = "%s FROM DUAL" % expression
for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
for sqlStatement in sqlStatements: for sqlStatement in sqlStatements:
if expression.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement": if expression.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement":

View File

@ -22,14 +22,72 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
""" """
try:
import cx_Oracle
except ImportError, _:
pass
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from plugins.generic.connector import Connector as GenericConnector from plugins.generic.connector import Connector as GenericConnector
class Connector(GenericConnector): class Connector(GenericConnector):
""" """
Homepage: Homepage: http://cx-oracle.sourceforge.net/
User guide: User guide: http://cx-oracle.sourceforge.net/README.txt
API: API: http://cx-oracle.sourceforge.net/html/index.html
Debian package: -
License: http://cx-oracle.sourceforge.net/LICENSE.txt
Possible connectors: -
""" """
def __init__(self): def __init__(self):
GenericConnector.__init__(self) GenericConnector.__init__(self)
def connect(self):
self.initConnection()
self.__dsn = cx_Oracle.makedsn(self.hostname, self.port, self.db)
try:
self.connector = cx_Oracle.connect(dsn=self.__dsn, user=self.user, password=self.password, mode=cx_Oracle.SYSDBA)
logger.info("successfully connected as SYSDBA")
except (cx_Oracle.OperationalError, cx_Oracle.DatabaseError), _:
try:
self.connector = cx_Oracle.connect(dsn=self.__dsn, user=self.user, password=self.password)
except (cx_Oracle.OperationalError, cx_Oracle.DatabaseError), msg:
raise sqlmapConnectionException, msg
self.setCursor()
self.connected()
def fetchall(self):
try:
return self.cursor.fetchall()
except cx_Oracle.InterfaceError, msg:
logger.log(8, msg)
return None
def execute(self, query):
logger.debug(query)
try:
self.cursor.execute(query)
except (cx_Oracle.DatabaseError), msg:
logger.log(8, msg)
except cx_Oracle.InternalError, msg:
raise sqlmapConnectionException, msg
self.connector.commit()
def select(self, query):
self.execute(query)
return self.fetchall()
def setCursor(self):
self.cursor = self.connector.cursor()
def close(self):
self.cursor.close()
self.connector.close()

View File

@ -22,6 +22,7 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
""" """
from lib.core.common import getRange
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
@ -49,7 +50,7 @@ class Enumeration(GenericEnumeration):
# Set containing the list of DBMS administrators # Set containing the list of DBMS administrators
areAdmins = set() areAdmins = set()
if kb.unionPosition: if kb.unionPosition or conf.direct:
if query2: if query2:
query = rootQuery["inband"]["query2"] query = rootQuery["inband"]["query2"]
condition = rootQuery["inband"]["condition2"] condition = rootQuery["inband"]["condition2"]

View File

@ -78,6 +78,12 @@ class Fingerprint(GenericFingerprint):
return value return value
def checkDbms(self): def checkDbms(self):
logMsg = "testing Oracle"
logger.info(logMsg)
if conf.direct:
conf.dbmsConnector.connect()
if conf.dbms in ORACLE_ALIASES: if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle") setDbms("Oracle")
@ -86,18 +92,25 @@ class Fingerprint(GenericFingerprint):
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
logMsg = "testing Oracle" # NOTE: SELECT ROWNUM=ROWNUM FROM DUAL does not work connecting
logger.info(logMsg) # directly to the Oracle database
if conf.direct:
payload = agent.fullPayload(" AND ROWNUM=ROWNUM") result = True
result = Request.queryPage(payload) else:
payload = agent.fullPayload(" AND ROWNUM=ROWNUM")
result = Request.queryPage(payload)
if result: if result:
logMsg = "confirming Oracle" logMsg = "confirming Oracle"
logger.info(logMsg) logger.info(logMsg)
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)") # NOTE: SELECT LENGTH(SYSDATE)=LENGTH(SYSDATE) FROM DUAL does
result = Request.queryPage(payload) # not work connecting directly to the Oracle database
if conf.direct:
result = True
else:
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)")
result = Request.queryPage(payload)
if not result: if not result:
warnMsg = "the back-end DMBS is not Oracle" warnMsg = "the back-end DMBS is not Oracle"

View File

@ -26,6 +26,9 @@ import os
import sys import sys
import time import time
import traceback import traceback
import warnings
warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning)
try: try:
import psyco import psyco