Added support to directly connect also to Microsoft SQL Server database.

Fixed direct connection to always use the same query as of UNION query SQL injection (= one query with multiple columns/entries output).
Minor fixes to Firebird/Access/SQLite connectors to use connector's execute()/fetchall() as wrapper for third-party libraries' methods.
Forced conf.timeout to 10 seconds when directly connecting to database.
Slightly improved regular expression to parse -d parameter.
Added import check for all connectors' third-party libraries.
Code refactoring:
* Moved conf.direct request to direct() function in lib/request/direct.py (code reused where needed).
* Back-delegated to generic connector close() and other methods.
This commit is contained in:
Bernardo Damele 2010-03-31 10:50:47 +00:00
parent d583cc07e7
commit 5fdebb5d5b
22 changed files with 205 additions and 223 deletions

View File

@ -65,9 +65,6 @@ def action():
raise sqlmapUnsupportedDBMSException, errMsg raise sqlmapUnsupportedDBMSException, errMsg
if conf.direct:
conf.dbmsConnector.connect()
print "%s\n" % conf.dbmsHandler.getFingerprint() print "%s\n" % conf.dbmsHandler.getFingerprint()
# Techniques options # Techniques options

View File

@ -79,6 +79,9 @@ def setHandler():
conf.dbmsConnector = dbmsConn() conf.dbmsConnector = dbmsConn()
if conf.direct: if conf.direct:
logger.debug("forcing timeout to 10 seconds")
conf.timeout = 10
conf.dbmsConnector.connect() conf.dbmsConnector.connect()
if handler.checkDbms(): if handler.checkDbms():

View File

@ -606,14 +606,14 @@ def parseTargetDirect():
details = None details = None
for dbms in SUPPORTED_DBMS: for dbms in SUPPORTED_DBMS:
details = re.search("^(?P<dbms>%s)://(?P<credentials>(?P<dbmsUser>.+?)\:(?P<dbmsPass>.+?)\@)?(?P<remote>(?P<hostname>.+?)\:(?P<port>[\d]+)\/)?(?P<dbmsDb>.+?)$" % dbms, conf.direct, re.I) details = re.search("^(?P<dbms>%s)://(?P<credentials>(?P<user>.+?)\:(?P<pass>.+?)\@)?(?P<remote>(?P<hostname>.+?)\:(?P<port>[\d]+)\/)?(?P<db>[\w\d\.\_\-\/]+?)$" % dbms, conf.direct, re.I)
if details: if details:
conf.dbms = details.group('dbms') conf.dbms = details.group('dbms')
if details.group('credentials'): if details.group('credentials'):
conf.dbmsUser = details.group('dbmsUser') conf.dbmsUser = details.group('user')
conf.dbmsPass = details.group('dbmsPass') conf.dbmsPass = details.group('pass')
else: else:
conf.dbmsUser = str() conf.dbmsUser = str()
conf.dbmsPass = str() conf.dbmsPass = str()
@ -625,30 +625,31 @@ def parseTargetDirect():
conf.hostname = "localhost" conf.hostname = "localhost"
conf.port = 0 conf.port = 0
conf.dbmsDb = details.group('dbmsDb') conf.dbmsDb = details.group('db')
conf.parameters[None] = "direct connection" conf.parameters[None] = "direct connection"
break break
if not details: if not details:
errMsg = "invalid target details, valid syntax is for instance: 'mysql://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_NAME'" errMsg = "invalid target details, valid syntax is for instance "
errMsg += " and/or: 'access://DATABASE_FILEPATH'" errMsg += "'mysql://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_NAME' "
errMsg += "or 'access://DATABASE_FILEPATH'"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
# TODO: add details for others python DBMS libraries
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, "python cx_Oracle", "http://cx-oracle.sourceforge.net/"], "Oracle": [ORACLE_ALIASES, "python cx_Oracle", "http://cx-oracle.sourceforge.net/"],
"SQLite": [SQLITE_ALIASES, "", ""], "SQLite": [SQLITE_ALIASES, "python-pysqlite2", "http://pysqlite.googlecode.com/"],
"Access": [ACCESS_ALIASES, "", ""], "Access": [ACCESS_ALIASES, "python-pyodbc", "http://pyodbc.googlecode.com/"],
"Firebird": [FIREBIRD_ALIASES, "", ""] } "Firebird": [FIREBIRD_ALIASES, "python-kinterbasdb", "http://kinterbasdb.sourceforge.net/"] }
for dbmsName, data in dbmsDict.items(): for dbmsName, data in dbmsDict.items():
if conf.dbms in data[0]: if conf.dbms in data[0]:
try: try:
if dbmsName == "Microsoft SQL Server": if dbmsName == "Microsoft SQL Server":
import _mssql
import pymssql import pymssql
elif dbmsName == "MySQL": elif dbmsName == "MySQL":
import MySQLdb import MySQLdb
@ -656,6 +657,12 @@ def parseTargetDirect():
import psycopg2 import psycopg2
elif dbmsName == "Oracle": elif dbmsName == "Oracle":
import cx_Oracle import cx_Oracle
elif dbmsName == "SQLite":
import sqlite3
elif dbmsName == "Access":
import pyodbc
elif dbmsName == "Firebird":
import kinterbasdb
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

@ -42,6 +42,7 @@ from lib.core.settings import SQL_STATEMENTS
from lib.request.basic import decodePage from lib.request.basic import decodePage
from lib.request.basic import forgeHeaders from lib.request.basic import forgeHeaders
from lib.request.basic import parseResponse from lib.request.basic import parseResponse
from lib.request.direct import direct
from lib.request.comparison import comparison from lib.request.comparison import comparison
@ -265,39 +266,7 @@ class Connect:
""" """
if conf.direct: if conf.direct:
values = None return direct(value, content)
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 sqlStatement in sqlStatements:
if value.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement":
select = True
break
if select:
values = conf.dbmsConnector.select(value)
else:
values = conf.dbmsConnector.execute(value)
if values is None or len(values) == 0:
return None
elif content:
if len(values) == 1:
if len(values[0]) == 1:
return str(list(values)[0][0]), None
else:
return list(values), None
else:
return values, None
else:
for value in values:
if value[0] in (1, -1):
return True
else:
return False
get = None get = None
post = None post = None

64
lib/request/direct.py Normal file
View File

@ -0,0 +1,64 @@
#!/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. <bernardo.damele@gmail.com>
Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
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.data import conf
from lib.core.data import kb
from lib.core.settings import SQL_STATEMENTS
def direct(query, content=True):
output = None
select = False
query = agent.payloadDirect(query)
if kb.dbms == "Oracle" and query.startswith("SELECT ") and " FROM " not in query:
query = "%s FROM DUAL" % query
for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
for sqlStatement in sqlStatements:
if query.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement":
select = True
break
if select:
output = conf.dbmsConnector.select(query)
else:
output = conf.dbmsConnector.execute(query)
if output is None or len(output) == 0:
return None
elif content:
if len(output) == 1:
if len(output[0]) == 1:
return str(list(output)[0][0])
else:
return list(output)
else:
return output
else:
for line in output:
if line[0] in (1, -1):
return True
else:
return False

View File

@ -37,6 +37,7 @@ from lib.core.data import logger
from lib.core.data import queries from lib.core.data import queries
from lib.core.data import temp from lib.core.data import temp
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.request.direct import direct
from lib.core.settings import SQL_STATEMENTS from lib.core.settings import SQL_STATEMENTS
from lib.techniques.inband.union.use import unionUse from lib.techniques.inband.union.use import unionUse
from lib.techniques.blind.inference import bisection from lib.techniques.blind.inference import bisection
@ -352,33 +353,7 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None,
""" """
if conf.direct: if conf.direct:
expression = agent.payloadDirect(expression) return direct(expression)
values = None
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 sqlStatement in sqlStatements:
if expression.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement":
select = True
break
if select:
values = conf.dbmsConnector.select(expression)
else:
values = conf.dbmsConnector.execute(expression)
if values is None or len(values) == 0:
return None
elif len(values) == 1:
if len(values[0]) == 1:
return str(list(values)[0][0])
else:
return list(values)
else:
return values
expression = cleanQuery(expression) expression = cleanQuery(expression)
expression = expandAsteriskForColumns(expression) expression = expandAsteriskForColumns(expression)
@ -418,25 +393,7 @@ def goStacked(expression, silent=False):
expression = cleanQuery(expression) expression = cleanQuery(expression)
if conf.direct: if conf.direct:
expression = agent.payloadDirect(expression) return direct(expression), None
values = None
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 sqlStatement in sqlStatements:
if expression.lower().startswith(sqlStatement) and sqlTitle == "SQL SELECT statement":
select = True
break
if select:
values = conf.dbmsConnector.select(expression)
else:
values = conf.dbmsConnector.execute(expression)
return None, None
debugMsg = "query: %s" % expression debugMsg = "query: %s" % expression
logger.debug(debugMsg) logger.debug(debugMsg)

View File

@ -45,15 +45,14 @@ class Connector(GenericConnector):
def __init__(self): def __init__(self):
GenericConnector.__init__(self) GenericConnector.__init__(self)
def connect(self, reuse=True): def connect(self):
if reuse and self.connector:
return
self.initConnection() self.initConnection()
self.checkFileDb()
try: try:
#self.connector = pyodbc.connect(driver='{Microsoft Access Driver (*.mdb)}', dbq=self.db, uid='Admin') #self.connector = pyodbc.connect(driver='{Microsoft Access Driver (*.mdb)}', dbq=self.db, uid='Admin')
self.connector = pyodbc.connect('Driver={Microsoft Access Driver (*.mdb)};Dbq=%s;Uid=Admin;Pwd=;' % self.db) self.connector = pyodbc.connect('Driver={Microsoft Access Driver (*.mdb)};Dbq=%s;Uid=Admin;Pwd=;' % self.db)
self.connector.timeout = conf.timeout
except pyodbc.OperationalError, msg: except pyodbc.OperationalError, msg:
raise sqlmapConnectionException, msg[1] raise sqlmapConnectionException, msg[1]
@ -63,7 +62,7 @@ class Connector(GenericConnector):
def fetchall(self): def fetchall(self):
try: try:
return self.cursor.fetchall() return self.cursor.fetchall()
except pyodbc.OperationalError, msg: except pyodbc.ProgrammingError, msg:
logger.log(8, msg[1]) logger.log(8, msg[1])
return None return None
@ -80,18 +79,5 @@ class Connector(GenericConnector):
self.connector.commit() self.connector.commit()
def select(self, query): def select(self, query):
try: self.execute(query)
self.cursor.execute(query) return self.fetchall()
return self.cursor.fetchall()
except pyodbc.ProgrammingError, msg:
logger.log(8, msg[1])
return None
def setCursor(self):
self.cursor = self.connector.cursor()
def close(self):
self.cursor.close()
self.connector.close()
self.closed()

View File

@ -140,6 +140,7 @@ class Fingerprint(GenericFingerprint):
def checkDbms(self): def checkDbms(self):
if conf.dbms in ACCESS_ALIASES: if conf.dbms in ACCESS_ALIASES:
setDbms("Microsoft Access") setDbms("Microsoft Access")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True

View File

@ -37,20 +37,21 @@ class Connector(GenericConnector):
""" """
Homepage: http://kinterbasdb.sourceforge.net/ Homepage: http://kinterbasdb.sourceforge.net/
User guide: http://kinterbasdb.sourceforge.net/dist_docs/usage.html User guide: http://kinterbasdb.sourceforge.net/dist_docs/usage.html
Debian package: python-kinterbasdb
License: BSD License: BSD
""" """
def __init__(self): def __init__(self):
GenericConnector.__init__(self) GenericConnector.__init__(self)
def connect(self, reuse=True): def connect(self):
if reuse and self.connector:
return
self.initConnection() self.initConnection()
if not self.hostname:
self.checkFileDb()
try: try:
self.connector = kinterbasdb.connect(database=self.db, user=self.user, password=self.password, timeout={'period': conf.timeout}) self.connector = kinterbasdb.connect(host=self.hostname, database=self.db, user=self.user, password=self.password, timeout={'period': conf.timeout})
except kinterbasdb.OperationalError, msg: except kinterbasdb.OperationalError, msg:
raise sqlmapConnectionException, msg[1] raise sqlmapConnectionException, msg[1]
@ -77,13 +78,5 @@ class Connector(GenericConnector):
self.connector.commit() self.connector.commit()
def select(self, query): def select(self, query):
self.cursor.execute(query) self.execute(query)
return self.cursor.fetchall() return self.fetchall()
def setCursor(self):
self.cursor = self.connector.cursor()
def close(self):
self.cursor.close()
self.connector.close()
self.closed()

View File

@ -23,10 +23,12 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
""" """
try: try:
import _mssql
import pymssql import pymssql
except ImportError, _: except ImportError, _:
pass pass
from lib.core.data import conf
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException from lib.core.exception import sqlmapConnectionException
@ -45,3 +47,38 @@ class Connector(GenericConnector):
def __init__(self): def __init__(self):
GenericConnector.__init__(self) GenericConnector.__init__(self)
def connect(self):
self.initConnection()
try:
self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout)
except pymssql.OperationalError, msg:
raise sqlmapConnectionException, msg
self.setCursor()
self.connected()
def fetchall(self):
try:
return self.cursor.fetchall()
except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg:
logger.log(8, msg)
return None
def execute(self, query):
logger.debug(query)
try:
self.cursor.execute(query)
except (pymssql.OperationalError, pymssql.ProgrammingError), msg:
logger.log(8, msg)
except pymssql.InternalError, msg:
raise sqlmapConnectionException, msg
def select(self, query):
self.execute(query)
value = self.fetchall()
self.connector.commit()
return value

View File

@ -61,7 +61,7 @@ class Enumeration(GenericEnumeration):
else: else:
dbs = [conf.db] dbs = [conf.db]
if kb.unionPosition: if kb.unionPosition or conf.direct:
for db in dbs: for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList: if conf.excludeSysDbs and db in self.excludeDbsList:
infoMsg = "skipping system database '%s'" % db infoMsg = "skipping system database '%s'" % db
@ -75,7 +75,7 @@ class Enumeration(GenericEnumeration):
if value: if value:
kb.data.cachedTables[db] = value kb.data.cachedTables[db] = value
if not kb.data.cachedTables: if not kb.data.cachedTables and not conf.direct:
for db in dbs: for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList: if conf.excludeSysDbs and db in self.excludeDbsList:
infoMsg = "skipping system database '%s'" % db infoMsg = "skipping system database '%s'" % db

View File

@ -97,8 +97,13 @@ class Fingerprint(GenericFingerprint):
infoMsg = "testing Microsoft SQL Server" infoMsg = "testing Microsoft SQL Server"
logger.info(infoMsg) logger.info(infoMsg)
payload = agent.fullPayload(" AND LEN(@@VERSION)=LEN(@@VERSION)") # NOTE: SELECT LEN(@@VERSION)=LEN(@@VERSION) FROM DUAL does not work connecting
result = Request.queryPage(payload) # directly to the Microsoft SQL Server database
if conf.direct:
result = True
else:
payload = agent.fullPayload(" AND LEN(@@VERSION)=LEN(@@VERSION)")
result = Request.queryPage(payload)
if result: if result:
infoMsg = "confirming Microsoft SQL Server" infoMsg = "confirming Microsoft SQL Server"

View File

@ -47,10 +47,7 @@ class Connector(GenericConnector):
def __init__(self): def __init__(self):
GenericConnector.__init__(self) GenericConnector.__init__(self)
def connect(self, reuse=True): def connect(self):
if reuse and self.connector:
return
self.initConnection() self.initConnection()
try: try:
@ -83,11 +80,3 @@ class Connector(GenericConnector):
def select(self, query): def select(self, query):
self.execute(query) self.execute(query)
return self.fetchall() return self.fetchall()
def setCursor(self):
self.cursor = self.connector.cursor()
def close(self):
self.cursor.close()
self.connector.close()
self.closed()

View File

@ -154,9 +154,6 @@ class Fingerprint(GenericFingerprint):
* http://dev.mysql.com/doc/refman/6.0/en/news-6-0-x.html (manual has been withdrawn) * http://dev.mysql.com/doc/refman/6.0/en/news-6-0-x.html (manual has been withdrawn)
""" """
infoMsg = "testing MySQL"
logger.info(infoMsg)
if conf.dbms in MYSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit(): if conf.dbms in MYSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("MySQL %s" % kb.dbmsVersion[0]) setDbms("MySQL %s" % kb.dbmsVersion[0])
@ -168,6 +165,9 @@ class Fingerprint(GenericFingerprint):
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
infoMsg = "testing MySQL"
logger.info(infoMsg)
randInt = str(randomInt(1)) randInt = str(randomInt(1))
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()") payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
result = Request.queryPage(payload) result = Request.queryPage(payload)

View File

@ -37,19 +37,13 @@ class Connector(GenericConnector):
Homepage: http://cx-oracle.sourceforge.net/ Homepage: http://cx-oracle.sourceforge.net/
User guide: http://cx-oracle.sourceforge.net/README.txt User guide: http://cx-oracle.sourceforge.net/README.txt
API: http://cx-oracle.sourceforge.net/html/index.html API: http://cx-oracle.sourceforge.net/html/index.html
Debian package: -
License: http://cx-oracle.sourceforge.net/LICENSE.txt 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, reuse=True): def connect(self):
if reuse and self.connector:
return
self.initConnection() self.initConnection()
self.__dsn = cx_Oracle.makedsn(self.hostname, self.port, self.db) self.__dsn = cx_Oracle.makedsn(self.hostname, self.port, self.db)
@ -87,11 +81,3 @@ class Connector(GenericConnector):
def select(self, query): def select(self, query):
self.execute(query) self.execute(query)
return self.fetchall() return self.fetchall()
def setCursor(self):
self.cursor = self.connector.cursor()
def close(self):
self.cursor.close()
self.connector.close()
self.closed()

View File

@ -96,7 +96,7 @@ class Enumeration(GenericEnumeration):
else: else:
kb.data.cachedUsersRoles[user] = list(roles) kb.data.cachedUsersRoles[user] = list(roles)
if not kb.data.cachedUsersRoles: if not kb.data.cachedUsersRoles and not conf.direct:
conditionChar = "=" conditionChar = "="
if conf.user: if conf.user:

View File

@ -78,9 +78,6 @@ class Fingerprint(GenericFingerprint):
return value return value
def checkDbms(self): def checkDbms(self):
logMsg = "testing Oracle"
logger.info(logMsg)
if conf.dbms in ORACLE_ALIASES: if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle") setDbms("Oracle")
@ -89,6 +86,9 @@ class Fingerprint(GenericFingerprint):
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
logMsg = "testing Oracle"
logger.info(logMsg)
# NOTE: SELECT ROWNUM=ROWNUM FROM DUAL does not work connecting # NOTE: SELECT ROWNUM=ROWNUM FROM DUAL does not work connecting
# directly to the Oracle database # directly to the Oracle database
if conf.direct: if conf.direct:

View File

@ -46,10 +46,7 @@ class Connector(GenericConnector):
def __init__(self): def __init__(self):
GenericConnector.__init__(self) GenericConnector.__init__(self)
def connect(self, reuse=True): def connect(self):
if reuse and self.connector:
return
self.initConnection() self.initConnection()
try: try:
@ -82,11 +79,3 @@ class Connector(GenericConnector):
def select(self, query): def select(self, query):
self.execute(query) self.execute(query)
return self.fetchall() return self.fetchall()
def setCursor(self):
self.cursor = self.connector.cursor()
def close(self):
self.cursor.close()
self.connector.close()
self.closed()

View File

@ -86,9 +86,6 @@ class Fingerprint(GenericFingerprint):
* http://www.postgresql.org/docs/8.4/interactive/release.html (up to 8.4.2) * http://www.postgresql.org/docs/8.4/interactive/release.html (up to 8.4.2)
""" """
infoMsg = "testing PostgreSQL"
logger.info(infoMsg)
if conf.dbms in PGSQL_ALIASES: if conf.dbms in PGSQL_ALIASES:
setDbms("PostgreSQL") setDbms("PostgreSQL")
@ -97,6 +94,9 @@ class Fingerprint(GenericFingerprint):
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
infoMsg = "testing PostgreSQL"
logger.info(infoMsg)
randInt = str(randomInt(1)) randInt = str(randomInt(1))
payload = agent.fullPayload(" AND %s::int=%s" % (randInt, randInt)) payload = agent.fullPayload(" AND %s::int=%s" % (randInt, randInt))

View File

@ -39,7 +39,7 @@ class Connector(GenericConnector):
User guide: http://docs.python.org/release/2.5/lib/module-sqlite3.html User guide: http://docs.python.org/release/2.5/lib/module-sqlite3.html
API: http://docs.python.org/library/sqlite3.html API: http://docs.python.org/library/sqlite3.html
Debian package: python-pysqlite2 Debian package: python-pysqlite2
License: zlib/libpng License: MIT
Possible connectors: http://wiki.python.org/moin/SQLite Possible connectors: http://wiki.python.org/moin/SQLite
""" """
@ -47,11 +47,9 @@ class Connector(GenericConnector):
def __init__(self): def __init__(self):
GenericConnector.__init__(self) GenericConnector.__init__(self)
def connect(self, reuse=True): def connect(self):
if reuse and self.connector:
return
self.initConnection() self.initConnection()
self.checkFileDb()
try: try:
self.connector = sqlite3.connect(database=self.db, timeout=conf.timeout) self.connector = sqlite3.connect(database=self.db, timeout=conf.timeout)
@ -75,19 +73,11 @@ class Connector(GenericConnector):
self.cursor.execute(query) self.cursor.execute(query)
except sqlite3.OperationalError, msg: except sqlite3.OperationalError, msg:
logger.log(8, msg[0]) logger.log(8, msg[0])
except sqlite3.Error, msg: except sqlite3.DatabaseError, msg:
raise sqlmapConnectionException, msg[0] raise sqlmapConnectionException, msg[0]
self.connector.commit() self.connector.commit()
def select(self, query): def select(self, query):
self.cursor.execute(query) self.execute(query)
return self.cursor.fetchall() return self.fetchall()
def setCursor(self):
self.cursor = self.connector.cursor()
def close(self):
self.cursor.close()
self.connector.close()
self.closed()

View File

@ -22,8 +22,11 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 021101301 USA Franklin St, Fifth Floor, Boston, MA 021101301 USA
""" """
import os
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapUndefinedMethod from lib.core.exception import sqlmapUndefinedMethod
class Connector: class Connector:
@ -48,12 +51,29 @@ class Connector:
logger.info(infoMsg) logger.info(infoMsg)
def closed(self): def closed(self):
self.connector = None
self.cursor = None
infoMsg = "connection to %s server %s" % (conf.dbms, self.hostname) infoMsg = "connection to %s server %s" % (conf.dbms, self.hostname)
infoMsg += ":%d closed" % self.port infoMsg += ":%d closed" % self.port
logger.info(infoMsg) logger.info(infoMsg)
self.connector = None
self.cursor = None
def setCursor(self):
self.cursor = self.connector.cursor()
def getCursor(self):
return self.cursor
def close(self):
self.cursor.close()
self.connector.close()
self.closed()
def checkFileDb(self):
if not os.path.exists(self.db):
errMsg = "the provided database file '%s' does not exist" % self.db
raise sqlmapFilePathException, errMsg
def connect(self): def connect(self):
errMsg = "'connect' method must be defined " errMsg = "'connect' method must be defined "
errMsg += "into the specific DBMS plugin" errMsg += "into the specific DBMS plugin"
@ -73,16 +93,3 @@ class Connector:
errMsg = "'select' method must be defined " errMsg = "'select' method must be defined "
errMsg += "into the specific DBMS plugin" errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg raise sqlmapUndefinedMethod, errMsg
def setCursor(self):
errMsg = "'setCursor' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
def getCursor(self):
return self.cursor
def close(self):
errMsg = "'close' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg

View File

@ -149,7 +149,7 @@ class Enumeration:
if value: if value:
kb.data.cachedUsers = value kb.data.cachedUsers = value
if not kb.data.cachedUsers: if not kb.data.cachedUsers and not conf.direct:
infoMsg = "fetching number of database users" infoMsg = "fetching number of database users"
logger.info(infoMsg) logger.info(infoMsg)
@ -232,7 +232,7 @@ class Enumeration:
else: else:
kb.data.cachedUsersPasswords[user].append(password) kb.data.cachedUsersPasswords[user].append(password)
if not kb.data.cachedUsersPasswords: if not kb.data.cachedUsersPasswords and not conf.direct:
if conf.user: if conf.user:
if "," in conf.user: if "," in conf.user:
users = conf.user.split(",") users = conf.user.split(",")
@ -464,7 +464,7 @@ class Enumeration:
else: else:
kb.data.cachedUsersPrivileges[user] = list(privileges) kb.data.cachedUsersPrivileges[user] = list(privileges)
if not kb.data.cachedUsersPrivileges: if not kb.data.cachedUsersPrivileges and not conf.direct:
conditionChar = "=" conditionChar = "="
if conf.user: if conf.user:
@ -649,7 +649,7 @@ class Enumeration:
if value: if value:
kb.data.cachedDbs = value kb.data.cachedDbs = value
if not kb.data.cachedDbs: if not kb.data.cachedDbs and not conf.direct:
infoMsg = "fetching number of databases" infoMsg = "fetching number of databases"
logger.info(infoMsg) logger.info(infoMsg)
@ -733,7 +733,7 @@ class Enumeration:
else: else:
kb.data.cachedTables[db].append(table) kb.data.cachedTables[db].append(table)
if not kb.data.cachedTables: if not kb.data.cachedTables and not conf.direct:
if conf.db: if conf.db:
if "," in conf.db: if "," in conf.db:
dbs = conf.db.split(",") dbs = conf.db.split(",")
@ -881,7 +881,7 @@ class Enumeration:
table[conf.tbl] = columns table[conf.tbl] = columns
kb.data.cachedColumns[conf.db] = table kb.data.cachedColumns[conf.db] = table
if not kb.data.cachedColumns: if not kb.data.cachedColumns and not conf.direct:
infoMsg = "fetching number of columns " infoMsg = "fetching number of columns "
infoMsg += "for table '%s'" % conf.tbl infoMsg += "for table '%s'" % conf.tbl
infoMsg += " on database '%s'" % conf.db infoMsg += " on database '%s'" % conf.db
@ -1298,8 +1298,10 @@ class Enumeration:
colList = conf.col.split(",") colList = conf.col.split(",")
kb.data.cachedColumns[conf.db] = {} kb.data.cachedColumns[conf.db] = {}
kb.data.cachedColumns[conf.db][conf.tbl] = {} kb.data.cachedColumns[conf.db][conf.tbl] = {}
for column in colList: for column in colList:
kb.data.cachedColumns[conf.db][conf.tbl][column] = None kb.data.cachedColumns[conf.db][conf.tbl][column] = None
elif not kb.data.cachedColumns: elif not kb.data.cachedColumns:
if kb.dbms == "MySQL" and not kb.data.has_information_schema: if kb.dbms == "MySQL" and not kb.data.has_information_schema:
errMsg = "information_schema not available, " errMsg = "information_schema not available, "
@ -1359,7 +1361,7 @@ class Enumeration:
index += 1 index += 1
if not kb.data.dumpedTable: if not kb.data.dumpedTable and not conf.direct:
infoMsg = "fetching number of " infoMsg = "fetching number of "
if conf.col: if conf.col:
infoMsg += "columns '%s' " % colString infoMsg += "columns '%s' " % colString