bulk of fixes

This commit is contained in:
Miroslav Stampar 2011-07-02 22:48:56 +00:00
parent 861cdb1b14
commit 34d9a91af1
8 changed files with 145 additions and 151 deletions

View File

@ -2767,3 +2767,18 @@ def expandMnemonics(mnemonics, parser, args):
else:
errMsg = "mnemonic '%s' requires value of type '%s'" % (name, found.type)
raise sqlmapSyntaxException, errMsg
def safeCSValue(value):
"""
Returns value safe for CSV dumping.
Reference: http://stackoverflow.com/questions/769621/dealing-with-commas-in-a-csv-file
"""
retVal = value
if isinstance(retVal, basestring):
if not (retVal[0] == retVal[-1] == '"'):
if any(map(lambda x: x in retVal, ['"', ',', '\n'])):
retVal = '"%s"' % retVal.replace('"', '""')
return retVal

View File

@ -18,6 +18,7 @@ from lib.core.common import getUnicode
from lib.core.common import normalizeUnicode
from lib.core.common import openFile
from lib.core.common import restoreDumpMarkedChars
from lib.core.common import safeCSValue
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@ -392,9 +393,9 @@ class Dump:
if not conf.replicate:
if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "%s" % column)
dataToDumpFile(dumpFP, "%s" % safeCSValue(column))
elif not conf.multipleTargets:
dataToDumpFile(dumpFP, "%s," % column)
dataToDumpFile(dumpFP, "%s," % safeCSValue(column))
field += 1
@ -432,9 +433,9 @@ class Dump:
if not conf.replicate:
if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % value)
dataToDumpFile(dumpFP, "%s" % safeCSValue(value))
elif not conf.multipleTargets:
dataToDumpFile(dumpFP, "\"%s\"," % value)
dataToDumpFile(dumpFP, "%s," % safeCSValue(value))
field += 1

View File

@ -11,11 +11,15 @@ import difflib
import threading
import time
from thread import error as threadError
from lib.core.data import kb
from lib.core.data import logger
from lib.core.datatype import advancedDict
from lib.core.enums import PAYLOAD
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapThreadException
from lib.core.exception import sqlmapValueException
from lib.core.settings import MAX_NUMBER_OF_THREADS
from lib.core.settings import PYVERSION
@ -68,7 +72,7 @@ def exceptionHandledFunction(threadFunction):
print
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardException=True, threadChoice=False):
def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardException=True, threadChoice=False, startThreadMsg=True):
threads = []
kb.multiThreadMode = True
@ -92,8 +96,9 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
logger.warn(warnMsg)
if numThreads > 1:
infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg)
if startThreadMsg:
infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg)
else:
threadFunction()
return
@ -108,7 +113,13 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
else:
thread.setDaemon(True)
thread.start()
try:
thread.start()
except threadError, errMsg:
errMsg = "error occured while starting new thread ('%s')" % errMsg
logger.critical(errMsg)
break
threads.append(thread)
# And wait for them to all finish
@ -122,11 +133,9 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
time.sleep(1)
except KeyboardInterrupt:
print
kb.threadContinue = False
kb.threadException = True
print '\r',
logger.info("waiting for threads to finish (Ctrl+C was pressed)")
try:
@ -139,6 +148,20 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
if forwardException:
raise
except (sqlmapConnectionException, sqlmapValueException), errMsg:
print
kb.threadException = True
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
except:
from lib.core.common import unhandledExceptionMessage
print
kb.threadException = True
errMsg = unhandledExceptionMessage()
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
traceback.print_exc()
finally:
kb.multiThreadMode = False
kb.bruteMode = False

View File

@ -44,6 +44,8 @@ from lib.core.settings import INFERENCE_GREATER_CHAR
from lib.core.settings import INFERENCE_EQUALS_CHAR
from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
from lib.core.settings import PYVERSION
from lib.core.threads import getCurrentThreadData
from lib.core.threads import runThreads
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
@ -301,26 +303,31 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# Go multi-threading (--threads > 1)
if conf.threads > 1 and isinstance(length, int) and length > 1:
value = [ None ] * length
index = [ firstChar ] # As list for python nested function scoping
idxlock = threading.Lock()
iolock = threading.Lock()
valuelock = threading.Lock()
kb.threadContinue = True
value = []
threadData = getCurrentThreadData()
threadData.shared.value = [ None ] * length
threadData.shared.index = [ firstChar ] # As list for python nested function scoping
lockNames = ('iolock', 'idxlock', 'valuelock')
for lock in lockNames:
kb.locks[lock] = threading.Lock()
try:
def blindThread():
threadData = getCurrentThreadData()
def downloadThread():
try:
while kb.threadContinue:
idxlock.acquire()
kb.locks.idxlock.acquire()
if index[0] >= length:
idxlock.release()
if threadData.shared.index[0] >= length:
kb.locks.idxlock.release()
return
index[0] += 1
curidx = index[0]
idxlock.release()
threadData.shared.index[0] += 1
curidx = threadData.shared.index[0]
kb.locks.idxlock.release()
if kb.threadContinue:
charStart = time.time()
@ -330,14 +337,14 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
else:
break
valuelock.acquire()
value[curidx-1] = val
currentValue = list(value)
valuelock.release()
kb.locks.valuelock.acquire()
threadData.shared.value[curidx-1] = val
currentValue = list(threadData.shared.value)
kb.locks.valuelock.release()
if kb.threadContinue:
if showEta:
etaProgressUpdate(time.time() - charStart, index[0])
etaProgressUpdate(time.time() - charStart, threadData.shared.index[0])
elif conf.verbose >= 1:
startCharIndex = 0
endCharIndex = 0
@ -370,14 +377,14 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
status = ' %d/%d (%d%s)' % (count, length, round(100.0*count/length), '%')
output += status if count != length else " "*len(status)
iolock.acquire()
kb.locks.iolock.acquire()
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output)))
iolock.release()
kb.locks.iolock.release()
if not kb.threadContinue:
if int(threading.currentThread().getName()) == numThreads - 1:
partialValue = unicode()
for v in value:
for v in threadData.shared.value:
if v is None:
break
elif isinstance(v, basestring):
@ -386,57 +393,14 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if len(partialValue) > 0:
dataToSessionFile(replaceNewlineTabs(partialValue))
except (sqlmapConnectionException, sqlmapValueException), errMsg:
print
kb.threadException = True
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
except KeyboardInterrupt:
kb.threadException = True
print
logger.debug("waiting for threads to finish")
try:
while (threading.activeCount() > 1):
pass
except KeyboardInterrupt:
raise sqlmapThreadException, "user aborted"
except:
print
kb.threadException = True
errMsg = unhandledExceptionMessage()
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
traceback.print_exc()
# Start the threads
for numThread in range(numThreads):
thread = threading.Thread(target=downloadThread, name=str(numThread))
if PYVERSION >= "2.6":
thread.daemon = True
else:
thread.setDaemon(True)
thread.start()
threads.append(thread)
# And wait for them to all finish
try:
alive = True
while alive:
alive = False
for thread in threads:
if thread.isAlive():
alive = True
time.sleep(1)
runThreads(numThreads, blindThread, startThreadMsg=False)
except KeyboardInterrupt:
kb.threadContinue = False
raise
finally:
value = threadData.shared.value
infoMsg = None
# If we have got one single character not correctly fetched it

View File

@ -318,22 +318,22 @@ def errorUse(expression, expected=None, resumeValue=True, dump=False):
stopLimit = 1
threadData = getCurrentThreadData()
threadData.shared.limits = range(startLimit, stopLimit)
numThreads = min(conf.threads, len(threadData.shared.limits))
threadData.shared.outputs = []
if stopLimit > TURN_OFF_RESUME_INFO_LIMIT:
kb.suppressResumeInfo = True
debugMsg = "suppressing possible resume console info because of "
debugMsg += "large number of rows. It might take too long"
logger.debug(debugMsg)
lockNames = ('limits', 'outputs')
for lock in lockNames:
kb.locks[lock] = threading.Lock()
try:
threadData = getCurrentThreadData()
threadData.shared.limits = range(startLimit, stopLimit)
numThreads = min(conf.threads, len(threadData.shared.limits))
threadData.shared.outputs = []
if stopLimit > TURN_OFF_RESUME_INFO_LIMIT:
kb.suppressResumeInfo = True
debugMsg = "suppressing possible resume console info because of "
debugMsg += "large number of rows. It might take too long"
logger.debug(debugMsg)
lockNames = ('limits', 'outputs')
for lock in lockNames:
kb.locks[lock] = threading.Lock()
def errorThread():
threadData = getCurrentThreadData()
@ -366,12 +366,6 @@ def errorUse(expression, expected=None, resumeValue=True, dump=False):
warnMsg += "will display partial output"
logger.warn(warnMsg)
except sqlmapConnectionException, e:
errMsg = "connection exception detected. sqlmap "
errMsg += "will display partial output"
errMsg += "'%s'" % e
logger.critical(errMsg)
finally:
outputs = threadData.shared.outputs
kb.suppressResumeInfo = False

View File

@ -259,22 +259,22 @@ def unionUse(expression, unpack=True, dump=False):
stopLimit = 1
threadData = getCurrentThreadData()
threadData.shared.limits = range(startLimit, stopLimit)
numThreads = min(conf.threads, len(threadData.shared.limits))
threadData.shared.value = ""
if stopLimit > TURN_OFF_RESUME_INFO_LIMIT:
kb.suppressResumeInfo = True
debugMsg = "suppressing possible resume console info because of "
debugMsg += "large number of rows. It might take too long"
logger.debug(debugMsg)
lockNames = ('limits', 'value')
for lock in lockNames:
kb.locks[lock] = threading.Lock()
try:
threadData = getCurrentThreadData()
threadData.shared.limits = range(startLimit, stopLimit)
numThreads = min(conf.threads, len(threadData.shared.limits))
threadData.shared.value = ""
if stopLimit > TURN_OFF_RESUME_INFO_LIMIT:
kb.suppressResumeInfo = True
debugMsg = "suppressing possible resume console info because of "
debugMsg += "large number of rows. It might take too long"
logger.debug(debugMsg)
lockNames = ('limits', 'value')
for lock in lockNames:
kb.locks[lock] = threading.Lock()
def unionThread():
threadData = getCurrentThreadData()
@ -334,12 +334,6 @@ def unionUse(expression, unpack=True, dump=False):
warnMsg += "will display partial output"
logger.warn(warnMsg)
except sqlmapConnectionException, e:
errMsg = "connection exception detected. sqlmap "
errMsg += "will display partial output"
errMsg += "'%s'" % e
logger.critical(errMsg)
finally:
value = threadData.shared.value
kb.suppressResumeInfo = False

View File

@ -13,6 +13,7 @@ import time
from lib.core.agent import agent
from lib.core.common import arrayizeValue
from lib.core.common import Backend
from lib.core.common import clearConsoleLine
from lib.core.common import dataToStdout
from lib.core.common import getRange
from lib.core.common import getCompiledRegex
@ -463,7 +464,7 @@ class Enumeration:
query += " WHERE "
if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
query += " OR ".join("%s LIKE '%%%s%%'" % (condition, user) for user in sorted(users))
query += " OR ".join("%s LIKE '%s'" % (condition, user) for user in sorted(users))
else:
query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users))
@ -1161,7 +1162,7 @@ class Enumeration:
infoMsg = "fetching columns "
if len(colList) > 0:
condQuery = " AND (%s)" % " OR ".join("%s LIKE '%%%s%%'" % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList))
condQuery = " AND (%s)" % " OR ".join("%s LIKE '%s'" % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList))
likeMsg = "like '%s' " % ", ".join(unsafeSQLIdentificatorNaming(col) for col in sorted(colList))
infoMsg += likeMsg
else:
@ -1703,30 +1704,36 @@ class Enumeration:
plusOne = False
indexRange = getRange(count, dump=True, plusOne=plusOne)
for index in indexRange:
for column in colList:
if column not in lengths:
lengths[column] = 0
try:
for index in indexRange:
for column in colList:
if column not in lengths:
lengths[column] = 0
if column not in entries:
entries[column] = []
if column not in entries:
entries[column] = []
if Backend.getIdentifiedDbms() in ( DBMS.MYSQL, DBMS.PGSQL ):
query = rootQuery.blind.query % (column, conf.db, conf.tbl, index)
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.blind.query % (column, column,
tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())),
index)
elif Backend.isDbms(DBMS.SQLITE):
query = rootQuery.blind.query % (column, tbl, index)
if Backend.getIdentifiedDbms() in ( DBMS.MYSQL, DBMS.PGSQL ):
query = rootQuery.blind.query % (column, conf.db, conf.tbl, index)
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
query = rootQuery.blind.query % (column, column,
tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())),
index)
elif Backend.isDbms(DBMS.SQLITE):
query = rootQuery.blind.query % (column, tbl, index)
elif Backend.isDbms(DBMS.FIREBIRD):
query = rootQuery.blind.query % (index, column, tbl)
elif Backend.isDbms(DBMS.FIREBIRD):
query = rootQuery.blind.query % (index, column, tbl)
value = inject.getValue(query, inband=False, error=False, dump=True)
value = inject.getValue(query, inband=False, error=False, dump=True)
lengths[column] = max(lengths[column], len(value) if value else 0)
entries[column].append(value)
lengths[column] = max(lengths[column], len(value) if value else 0)
entries[column].append(value)
except KeyboardInterrupt:
clearConsoleLine()
warnMsg = "Ctrl+C detected in dumping phase"
logger.warn(warnMsg)
for column, columnEntries in entries.items():
length = max(lengths[column], len(column))
@ -1750,10 +1757,6 @@ class Enumeration:
warnMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
logger.warn(warnMsg)
except KeyboardInterrupt:
warnMsg = "Ctrl+C detected in dumping phase"
logger.warn(warnMsg)
except sqlmapConnectionException, e:
errMsg = "connection exception detected in dumping phase: "
errMsg += "'%s'" % e

View File

@ -156,14 +156,14 @@ class Miscellaneous:
def likeOrExact(self, what):
message = "do you want sqlmap to consider provided %s(s):\n" % what
message += "[1] as LIKE %s names (default)\n" % what
message += "[2] as exact %s names" % what
message += "[1] as LIKE %s names\n" % what
message += "[2] as exact %s names (default)" % what
choice = readInput(message, default="1")
choice = readInput(message, default="2")
if not choice or choice == "1":
choice = "1"
condParam = " LIKE '%%%s%%'"
condParam = " LIKE '%%%s%%'" # this doesn't work, neither not sure it ever did
elif choice.isdigit() and choice == "2":
condParam = "='%s'"
else: