sqlmap/lib/core/threads.py

218 lines
6.5 KiB
Python
Raw Normal View History

#!/usr/bin/env python
"""
2017-01-02 16:19:18 +03:00
Copyright (c) 2006-2017 sqlmap developers (http://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
"""
import difflib
2016-04-08 15:41:34 +03:00
import random
import threading
import time
2011-10-20 01:35:01 +04:00
import traceback
2011-11-22 14:41:56 +04:00
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
2011-07-08 10:02:31 +04:00
from lib.core.datatype import AttribDict
2011-06-28 01:48:26 +04:00
from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapThreadException
2016-10-18 14:37:36 +03:00
from lib.core.exception import SqlmapUserQuitException
from lib.core.exception import SqlmapValueException
from lib.core.settings import MAX_NUMBER_OF_THREADS
from lib.core.settings import PYVERSION
2011-07-08 10:02:31 +04:00
shared = AttribDict()
class _ThreadData(threading.local):
"""
Represents thread independent data
"""
def __init__(self):
2011-11-23 18:26:40 +04:00
self.reset()
def reset(self):
"""
Resets thread data model
"""
2011-04-30 17:20:05 +04:00
self.disableStdOut = False
2011-09-26 17:36:08 +04:00
self.hashDBCursor = None
2011-11-23 18:26:40 +04:00
self.inTransaction = False
self.lastCode = None
self.lastComparisonPage = None
self.lastComparisonHeaders = None
2016-06-03 15:29:32 +03:00
self.lastComparisonCode = None
2017-02-06 15:28:33 +03:00
self.lastComparisonRatio = None
2011-04-30 17:20:05 +04:00
self.lastErrorPage = None
self.lastHTTPError = None
self.lastRedirectMsg = None
self.lastQueryDuration = 0
self.lastPage = None
self.lastRequestMsg = None
2011-04-30 17:20:05 +04:00
self.lastRequestUID = 0
2013-04-30 20:08:26 +04:00
self.lastRedirectURL = None
2016-04-08 15:41:34 +03:00
self.random = random.WichmannHill()
2011-10-12 02:40:00 +04:00
self.resumed = False
2011-05-11 16:54:33 +04:00
self.retriesCount = 0
2011-04-30 17:20:05 +04:00
self.seqMatcher = difflib.SequenceMatcher(None)
self.shared = shared
2016-09-27 15:03:59 +03:00
self.validationRun = 0
2011-04-30 17:20:05 +04:00
self.valueStack = []
ThreadData = _ThreadData()
def getCurrentThreadUID():
return hash(threading.currentThread())
2017-04-18 16:48:05 +03:00
def readInput(message, default=None, checkBatch=True, boolean=False):
2012-02-16 13:54:29 +04:00
# It will be overwritten by original from lib.core.common
pass
def getCurrentThreadData():
"""
Returns current thread's local data
"""
global ThreadData
return ThreadData
def getCurrentThreadName():
"""
Returns current's thread name
"""
return threading.current_thread().getName()
2017-04-19 14:35:36 +03:00
def exceptionHandledFunction(threadFunction, silent=False):
try:
threadFunction()
except KeyboardInterrupt:
kb.threadContinue = False
kb.threadException = True
raise
2015-09-08 12:10:47 +03:00
except Exception, ex:
2017-04-19 14:35:36 +03:00
if not silent:
logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message))
def setDaemon(thread):
# Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation
if PYVERSION >= "2.6":
thread.daemon = True
else:
thread.setDaemon(True)
2011-07-03 02:48:56 +04:00
def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardException=True, threadChoice=False, startThreadMsg=True):
threads = []
kb.multiThreadMode = True
kb.threadContinue = True
kb.threadException = False
if threadChoice and numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)):
while True:
message = "please enter number of threads? [Enter for %d (current)] " % numThreads
choice = readInput(message, default=str(numThreads))
if choice:
skipThreadCheck = False
if choice.endswith('!'):
choice = choice[:-1]
skipThreadCheck = True
if choice.isdigit():
if int(choice) > MAX_NUMBER_OF_THREADS and not skipThreadCheck:
errMsg = "maximum number of used threads is %d avoiding potential connection issues" % MAX_NUMBER_OF_THREADS
logger.critical(errMsg)
else:
conf.threads = numThreads = int(choice)
break
if numThreads == 1:
warnMsg = "running in a single-thread mode. This could take a while"
logger.warn(warnMsg)
try:
if numThreads > 1:
if startThreadMsg:
infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg)
else:
threadFunction()
return
# Start the threads
for numThread in xrange(numThreads):
thread = threading.Thread(target=exceptionHandledFunction, name=str(numThread), args=[threadFunction])
setDaemon(thread)
try:
thread.start()
2017-04-14 14:14:53 +03:00
except Exception, ex:
2015-09-08 12:10:47 +03:00
errMsg = "error occurred while starting new thread ('%s')" % ex.message
logger.critical(errMsg)
break
2011-07-03 02:48:56 +04:00
threads.append(thread)
# And wait for them to all finish
alive = True
while alive:
alive = False
for thread in threads:
if thread.isAlive():
alive = True
2011-10-10 18:47:48 +04:00
time.sleep(0.1)
2016-10-18 14:37:36 +03:00
except (KeyboardInterrupt, SqlmapUserQuitException), ex:
2011-07-03 02:48:56 +04:00
print
kb.threadContinue = False
kb.threadException = True
2011-12-26 18:31:59 +04:00
if numThreads > 1:
2016-10-18 14:37:36 +03:00
logger.info("waiting for threads to finish%s" % (" (Ctrl+C was pressed)" if isinstance(ex, KeyboardInterrupt) else ""))
try:
while (threading.activeCount() > 1):
pass
except KeyboardInterrupt:
raise SqlmapThreadException("user aborted (Ctrl+C was pressed multiple times)")
2011-05-30 03:56:41 +04:00
if forwardException:
raise
2015-09-08 12:10:47 +03:00
except (SqlmapConnectionException, SqlmapValueException), ex:
2012-01-13 19:56:50 +04:00
print
kb.threadException = True
2015-09-08 12:10:47 +03:00
logger.error("thread %s: %s" % (threading.currentThread().getName(), ex.message))
2012-01-13 19:56:50 +04:00
except:
from lib.core.common import unhandledExceptionMessage
2011-07-03 02:48:56 +04:00
print
kb.threadException = True
2012-01-13 19:56:50 +04:00
errMsg = unhandledExceptionMessage()
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
2012-01-13 19:56:50 +04:00
traceback.print_exc()
2011-07-03 02:48:56 +04:00
finally:
kb.multiThreadMode = False
kb.bruteMode = False
kb.threadContinue = True
kb.threadException = False
2011-12-28 20:27:17 +04:00
for lock in kb.locks.values():
2016-06-10 19:02:24 +03:00
if lock.locked():
2016-03-22 15:24:54 +03:00
try:
lock.release()
2017-04-14 14:14:53 +03:00
except:
2016-03-22 15:24:54 +03:00
pass
2011-12-28 20:27:17 +04:00
2012-08-21 12:28:25 +04:00
if conf.get("hashDB"):
2011-11-23 07:03:31 +04:00
conf.hashDB.flush(True)
2011-11-22 14:41:56 +04:00
if cleanupFunction:
cleanupFunction()