forked from sqlmapproject/sqlmap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paththreads.py
202 lines (162 loc) · 5.76 KB
/
threads.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#!/usr/bin/env python
"""
Copyright (c) 2006-2012 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""
import difflib
import threading
import time
import traceback
from thread import error as threadError
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.datatype import AttribDict
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
shared = AttribDict()
class _ThreadData(threading.local):
"""
Represents thread independent data
"""
def __init__(self):
self.reset()
def reset(self):
"""
Resets thread data model
"""
self.disableStdOut = False
self.hashDBCursor = None
self.inTransaction = False
self.lastComparisonPage = None
self.lastErrorPage = None
self.lastHTTPError = None
self.lastRedirectMsg = None
self.lastQueryDuration = 0
self.lastRequestMsg = None
self.lastRequestUID = 0
self.resumed = False
self.retriesCount = 0
self.seqMatcher = difflib.SequenceMatcher(None)
self.shared = shared
self.valueStack = []
ThreadData = _ThreadData()
def getCurrentThreadUID():
return hash(threading.currentThread())
def readInput(message, default=None):
# 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()
def exceptionHandledFunction(threadFunction):
try:
threadFunction()
except KeyboardInterrupt:
kb.threadContinue = False
kb.threadException = True
raise
except Exception, errMsg:
# thread is just going to be silently killed
print
logger.error("thread %s: %s" % (threading.currentThread().getName(), errMsg))
def setDaemon(thread):
# Reference: http://stackoverflow.com/questions/190010/daemon-threads-explanation
if PYVERSION >= "2.6":
thread.daemon = True
else:
thread.setDaemon(True)
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 any(map(lambda x: x in kb.injection.data, [PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.UNION])):
while True:
message = "please enter number of threads? [Enter for %d (current)] " % numThreads
choice = readInput(message, default=str(numThreads))
if choice and choice.isdigit():
if int(choice) > MAX_NUMBER_OF_THREADS:
errMsg = "maximum number of used threads is %d avoiding possible connection issues" % MAX_NUMBER_OF_THREADS
logger.critical(errMsg)
else:
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()
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
alive = True
while alive:
alive = False
for thread in threads:
if thread.isAlive():
alive = True
time.sleep(0.1)
except KeyboardInterrupt:
print
kb.threadContinue = False
kb.threadException = True
if numThreads > 1:
logger.info("waiting for threads to finish (Ctrl+C was pressed)")
try:
while (threading.activeCount() > 1):
pass
except KeyboardInterrupt:
raise sqlmapThreadException, "user aborted (Ctrl+C was pressed multiple times)"
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
kb.threadContinue = True
kb.threadException = False
for lock in kb.locks.values():
if lock.locked_lock():
lock.release()
if conf.get("hashDB"):
conf.hashDB.flush(True)
if cleanupFunction:
cleanupFunction()