changes regarding EXISTS feature

This commit is contained in:
Miroslav Stampar 2010-09-30 12:35:45 +00:00
parent 51beafc32c
commit cf8e92699c
6 changed files with 120 additions and 21 deletions

View File

@ -27,6 +27,7 @@ from lib.core.common import getHtmlErrorFp
from lib.core.common import dataToStdout
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import paths
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.settings import SUPPORTED_DBMS
from lib.techniques.blind.timebased import timeTest
@ -111,6 +112,12 @@ def action():
if conf.getTables:
conf.dumper.dbTables(conf.dbmsHandler.getTables())
if conf.cExists:
conf.dumper.dbTables(conf.dbmsHandler.tableExists(paths.COMMON_TABLES))
if conf.tableFile:
conf.dumper.dbTables(conf.dbmsHandler.tableExists(conf.tableFile))
if conf.getColumns:
conf.dumper.dbTableColumns(conf.dbmsHandler.getColumns())

View File

@ -411,8 +411,8 @@ def filePathToString(filePath):
return strRepl
def dataToStdout(data):
if conf.verbose > 0:
def dataToStdout(data, forceOutput=False):
if conf.verbose > 0 or forceOutput:
try:
sys.stdout.write(data)
sys.stdout.flush()
@ -657,6 +657,8 @@ def setPaths():
# sqlmap files
paths.SQLMAP_HISTORY = os.path.join(paths.SQLMAP_ROOT_PATH, ".sqlmap_history")
paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr())
paths.COMMON_OUTPUTS = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
paths.COMMON_TABLES = os.path.join(paths.SQLMAP_TXT_PATH, "common-tables.txt")
paths.FUZZ_VECTORS = os.path.join(paths.SQLMAP_TXT_PATH, "fuzz_vectors.txt")
paths.DETECTION_RULES_XML = os.path.join(paths.SQLMAP_XML_PATH, "detection.xml")
paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
@ -1233,8 +1235,7 @@ def initCommonOutputs():
kb.commonOutputs = {}
key = None
fileName = os.path.join(paths.SQLMAP_TXT_PATH, 'common-outputs.txt')
cfile = codecs.open(fileName, 'r', conf.dataEncoding)
cfile = codecs.open(paths.COMMON_OUTPUTS, 'r', conf.dataEncoding)
for line in cfile.readlines(): # xreadlines doesn't return unicode strings when codec.open() is used
if line.find('#') != -1:
@ -1254,6 +1255,21 @@ def initCommonOutputs():
cfile.close()
def getFileItems(filename):
retVal = []
checkFile(filename)
file = codecs.open(filename, 'r', conf.dataEncoding)
for line in file.readlines(): # xreadlines doesn't return unicode strings when codec.open() is used
if line.find('#') != -1:
line = line[:line.find('#')]
line = line.strip()
if line:
retVal.append(line)
return retVal
def goGoodSamaritan(prevValue, originalCharset):
"""
Function for retrieving parameters needed for common prediction (good
@ -1411,4 +1427,10 @@ def replaceSpaces(query):
if query:
return query if conf.space is None else query.replace(' ', conf.space)
else:
return query
return query
def pushValue(value):
kb.valueStack.append(value)
def popValue():
return kb.valueStack.pop()

View File

@ -157,37 +157,58 @@ class Dump:
self.lister("available databases", dbs)
def dbTables(self, dbTables):
if not isinstance(dbTables, dict):
self.string("tables", dbTables)
if isinstance(dbTables, list):
maxlength = 0
return
maxlength = 0
for tables in dbTables.values():
for table in tables:
for table in dbTables:
maxlength = max(maxlength, len(table))
lines = "-" * (int(maxlength) + 2)
lines = "-" * (int(maxlength) + 2)
for db, tables in dbTables.items():
tables.sort(key=lambda x: x.lower())
dbTables.sort(key=lambda x: x.lower())
self.__write("Database: %s" % db)
if len(tables) == 1:
if len(dbTables) == 1:
self.__write("[1 table]")
else:
self.__write("[%d tables]" % len(tables))
self.__write("[%d tables]" % len(dbTables))
self.__write("+%s+" % lines)
for table in tables:
for table in dbTables:
blank = " " * (maxlength - len(table))
self.__write("| %s%s |" % (table, blank))
self.__write("+%s+\n" % lines)
elif isinstance(dbTables, dict):
maxlength = 0
for tables in dbTables.values():
for table in tables:
maxlength = max(maxlength, len(table))
lines = "-" * (int(maxlength) + 2)
for db, tables in dbTables.items():
tables.sort(key=lambda x: x.lower())
self.__write("Database: %s" % db)
if len(tables) == 1:
self.__write("[1 table]")
else:
self.__write("[%d tables]" % len(tables))
self.__write("+%s+" % lines)
for table in tables:
blank = " " * (maxlength - len(table))
self.__write("| %s%s |" % (table, blank))
self.__write("+%s+\n" % lines)
else:
self.string("tables", dbTables)
def dbTableColumns(self, tableColumns):
for db, tables in tableColumns.items():
if not db:

View File

@ -1031,6 +1031,7 @@ def __setKnowledgeBaseAttributes():
kb.unionPosition = None
kb.unionNegative = False
kb.unionFalseCond = False
kb.valueStack = []
def __saveCmdline():
"""

View File

@ -332,6 +332,12 @@ def cmdLineParser():
action="store_true", default=False,
help="Prompt for an interactive SQL shell")
enumeration.add_option("--common-exists", dest="cExists", action="store_true",
default=False, help="Check existence of common tables")
enumeration.add_option("--exists", dest="tableFile",
help="Check existence of user specified tables")
# User-defined function options
udf = OptionGroup(parser, "User-defined function injection", "These "
"options can be used to create custom user-defined "

View File

@ -23,12 +23,18 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
import time
from lib.core.agent import agent
from lib.core.common import dataToStdout
from lib.core.common import getRange
from lib.core.common import getCompiledRegex
from lib.core.common import getConsoleWidth
from lib.core.common import getFileItems
from lib.core.common import getUnicode
from lib.core.common import parsePasswordHash
from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import readInput
from lib.core.common import safeStringFormat
from lib.core.convert import urlencode
@ -47,6 +53,7 @@ from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest
from lib.techniques.outband.stacked import stackedTest
@ -801,6 +808,41 @@ class Enumeration:
return kb.data.cachedTables
def tableExists(self, tableFile):
tables = getFileItems(tableFile)
retVal = []
infoMsg = "checking tables existence using items from '%s'" % tableFile
logger.info(infoMsg)
pushValue(conf.verbose)
conf.verbose = 0
count = 0
length = len(tables)
for table in tables:
query = agent.prefixQuery(" %s" % safeStringFormat("AND EXISTS(SELECT 1 FROM %s)", table))
query = agent.postfixQuery(query)
result = Request.queryPage(urlencode(agent.payload(newValue=query)))
if result:
infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), table)
infoMsg = "%s%s\n" % (infoMsg, " "*(getConsoleWidth()-1-len(infoMsg)))
dataToStdout(infoMsg, True)
retVal.append(table)
count += 1
status = '%d/%d (%d%s)' % (count, length, round(100.0*count/length), '%')
dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status), True)
conf.verbose = popValue()
dataToStdout("\r%s\n" % (" "*(getConsoleWidth()-1)), True)
if not retVal:
warnMsg = "no table found"
logger.warn(warnMsg)
return retVal
def getColumns(self, onlyColNames=False):
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
errMsg = "information_schema not available, "