Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9de1671

Browse files
committed
Code refactoring and minor bug fixes.
1 parent c431a74 commit 9de1671

3 files changed

Lines changed: 106 additions & 57 deletions

File tree

lib/core/common.py

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from lib.core.exception import sqlmapNoneDataException
5858
from lib.core.exception import sqlmapMissingDependence
5959
from lib.core.exception import sqlmapSyntaxException
60+
from lib.core.optiondict import optDict
6061
from lib.core.settings import DESCRIPTION
6162
from lib.core.settings import IS_WIN
6263
from lib.core.settings import PLATFORM
@@ -417,7 +418,7 @@ def fileToStr(fileName):
417418
@rtype: C{str}
418419
"""
419420

420-
filePointer = codecs.open(fileName, "r", conf.dataEncoding)
421+
filePointer = codecs.open(fileName, "rb", conf.dataEncoding)
421422
fileText = filePointer.read()
422423

423424
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
@@ -1106,7 +1107,8 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
11061107
import gtk
11071108
import pydot
11081109
except ImportError, e:
1109-
logger.error(e)
1110+
errMsg = "profiling requires third-party libraries (%s)" % str(e)
1111+
logger.error(errMsg)
11101112
return
11111113

11121114
if profileOutputFile is None:
@@ -1209,6 +1211,9 @@ def initCommonOutputs():
12091211
for line in cfile.xreadlines():
12101212
line = line.strip()
12111213

1214+
if line.startswith('#'):
1215+
continue
1216+
12121217
if len(line) > 1:
12131218
if line[0] == '[' and line[-1] == ']':
12141219
key = line[1:-1]
@@ -1220,20 +1225,27 @@ def initCommonOutputs():
12201225

12211226
cfile.close()
12221227

1223-
def getGoodSamaritanParameters(part, prevValue, originalCharset):
1228+
def goGoodSamaritan(part, prevValue, originalCharset):
12241229
"""
1225-
Function for retrieving parameters needed for good samaritan (common outputs) feature.
1226-
Returns singleValue if there is a complete single match (in part of common-outputs.txt set by parameter 'part')
1227-
regarding parameter prevValue. If there is no single value match, but multiple, predictedCharset is returned
1228-
containing more probable characters (retrieved from matched items in common-outputs.txt) together with the
1229-
rest of charset as otherCharset
1230+
Function for retrieving parameters needed for common prediction (good
1231+
samaritan) feature.
1232+
1233+
part is for instance Users, Databases, Tables and corresponds to the
1234+
header (e.g. [Users]) in txt/common-outputs.txt.
1235+
1236+
prevValue: retrieved query output so far (e.g. 'i').
1237+
1238+
Returns singleValue if there is a complete single match (in part of
1239+
txt/common-outputs.txt under 'part') regarding parameter prevValue. If
1240+
there is no single value match, but multiple, commonCharset is
1241+
returned containing more probable characters (retrieved from matched
1242+
values in txt/common-outputs.txt) together with the rest of charset as
1243+
otherCharset.
12301244
"""
1245+
12311246
if kb.commonOutputs is None:
12321247
initCommonOutputs()
12331248

1234-
if not part or not prevValue: #is not None and != ""
1235-
return None, None, originalCharset
1236-
12371249
predictionSet = set()
12381250
wildIndexes = []
12391251
singleValue = None
@@ -1249,38 +1261,47 @@ def getGoodSamaritanParameters(part, prevValue, originalCharset):
12491261
charIndex += 1
12501262
findIndex = prevValue.find('.', charIndex)
12511263

1264+
# If the header we are looking for has common outputs defined
12521265
if part in kb.commonOutputs:
12531266
for item in kb.commonOutputs[part]:
1267+
# Check if the common output (item) starts with prevValue
12541268
if re.search('\A%s' % prevValue, item):
12551269
singleValue = item
1270+
12561271
for index in wildIndexes:
12571272
char = item[index]
12581273

12591274
if char not in predictionSet:
12601275
predictionSet.add(char)
12611276

1262-
predictedCharset = []
1277+
commonCharset = []
12631278
otherCharset = []
12641279

1280+
# Split the original charset into common chars (commonCharset)
1281+
# and other chars (otherCharset)
12651282
for ordChar in originalCharset:
12661283
if chr(ordChar) not in predictionSet:
12671284
otherCharset.append(ordChar)
12681285
else:
1269-
predictedCharset.append(ordChar)
1286+
commonCharset.append(ordChar)
12701287

1271-
predictedCharset.sort()
1288+
commonCharset.sort()
12721289

1273-
if len(predictedCharset) > 1:
1274-
return None, predictedCharset, otherCharset
1290+
if len(commonCharset) > 1:
1291+
return None, commonCharset, otherCharset
12751292
else:
12761293
return singleValue, None, originalCharset
12771294
else:
12781295
return None, None, originalCharset
12791296

12801297
def getCompiledRegex(regex, *args):
12811298
"""
1282-
Returns compiled regular expression and stores it in cache for further usage
1299+
Returns compiled regular expression and stores it in cache for further
1300+
usage
12831301
"""
1302+
1303+
global __compiledRegularExpressions
1304+
12841305
if (regex, args) in __compiledRegularExpressions:
12851306
return __compiledRegularExpressions[(regex, args)]
12861307
else:
@@ -1290,15 +1311,23 @@ def getCompiledRegex(regex, *args):
12901311

12911312
def getPartRun():
12921313
"""
1293-
Goes through call stack and finds constructs matching conf.dmbsHandler.*. Returns it or it's alias used in common-outputs.txt
1314+
Goes through call stack and finds constructs matching conf.dmbsHandler.*.
1315+
Returns it or its alias used in txt/common-outputs.txt
12941316
"""
1295-
commonPartsDict = { "getTables":"Tables", "getColumns":"Columns", "getUsers":"Users", "getBanner":"Banners", "getDbs":"Databases" }
1317+
12961318
retVal = None
1319+
commonPartsDict = optDict["Enumeration"]
12971320
stack = [item[4][0] if isinstance(item[4], list) else '' for item in inspect.stack()]
12981321
reobj = getCompiledRegex('conf\.dbmsHandler\.([^(]+)\(\)')
1322+
1323+
# Goes backwards through the stack to find the conf.dbmsHandler method
1324+
# calling this function
12991325
for i in xrange(len(stack) - 1, 0, -1):
13001326
match = reobj.search(stack[i])
1327+
13011328
if match:
1329+
# This is the calling conf.dbmsHandler method (e.g. 'getDbms')
13021330
retVal = match.groups()[0]
13031331
break
1304-
return commonPartsDict[retVal] if retVal in commonPartsDict else retVal
1332+
1333+
return commonPartsDict[retVal][1] if retVal in commonPartsDict else retVal

lib/core/optiondict.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
"""
2424

2525
optDict = {
26-
# Family: { "parameter_name": "parameter_datatype" },
26+
# Format:
27+
# Family: { "parameter name": "parameter datatype" },
28+
# Or:
29+
# Family: { "parameter name": ("parameter datatype", "category name used for common outputs feature") },
2730
"Target": {
2831
"direct": "string",
2932
"url": "string",
@@ -84,17 +87,17 @@
8487
},
8588

8689
"Enumeration": {
87-
"getBanner": "boolean",
88-
"getCurrentUser": "boolean",
89-
"getCurrentDb": "boolean",
90+
"getBanner": ("boolean", "Banners"),
91+
"getCurrentUser": ("boolean", "Users"),
92+
"getCurrentDb": ("boolean", "Databases"),
9093
"isDba": "boolean",
91-
"getUsers": "boolean",
92-
"getPasswordHashes": "boolean",
93-
"getPrivileges": "boolean",
94-
"getRoles": "boolean",
95-
"getDbs": "boolean",
96-
"getTables": "boolean",
97-
"getColumns": "boolean",
94+
"getUsers": ("boolean", "Users"),
95+
"getPasswordHashes": ("boolean", "Hashes"),
96+
"getPrivileges": ("boolean", "Privileges"),
97+
"getRoles": ("boolean", "Roles"),
98+
"getDbs": ("boolean", "Databases"),
99+
"getTables": ("boolean", "Tables"),
100+
"getColumns": ("boolean", "Columns"),
98101
"dumpTable": "boolean",
99102
"dumpAll": "boolean",
100103
"search": "boolean",
@@ -107,6 +110,8 @@
107110
"limitStop": "integer",
108111
"firstChar": "integer",
109112
"lastChar": "integer",
113+
"getNumOfTables": "integer",
114+
"getNumOfDBs": "integer",
110115
"query": "string",
111116
"sqlShell": "boolean"
112117
},
@@ -144,6 +149,7 @@
144149
},
145150

146151
"Miscellaneous": {
152+
"xmlFile": "string",
147153
"sessionFile": "string",
148154
"flushSession": "boolean",
149155
"eta": "boolean",

lib/techniques/blind/inference.py

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from lib.core.common import dataToSessionFile
3131
from lib.core.common import dataToStdout
3232
from lib.core.common import getCharset
33-
from lib.core.common import getGoodSamaritanParameters
33+
from lib.core.common import goGoodSamaritan
3434
from lib.core.common import getPartRun
3535
from lib.core.common import replaceNewlineTabs
3636
from lib.core.common import safeStringFormat
@@ -53,11 +53,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
5353
"""
5454

5555
partialValue = ""
56-
finalValue = ""
57-
56+
finalValue = ""
5857
asciiTbl = getCharset(charsetType)
5958

60-
kb.partRun = getPartRun() if conf.useCommonPrediction else None #set kb.partRun in case common-prediction used
59+
# Set kb.partRun in case "common prediction" feature (a.k.a. "good
60+
# samaritan") is used
61+
kb.partRun = getPartRun() if conf.useCommonPrediction else None
6162

6263
if "LENGTH(" in expression or "LEN(" in expression:
6364
firstChar = 0
@@ -116,9 +117,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
116117
else:
117118
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
118119

119-
queriesCount = [0] # As list to deal with nested scoping rules
120-
121-
hintlock = threading.Lock()
120+
queriesCount = [0] # As list to deal with nested scoping rules
121+
hintlock = threading.Lock()
122122

123123
def tryHint(idx):
124124
hintlock.acquire()
@@ -131,9 +131,9 @@ def tryHint(idx):
131131
else:
132132
posValue = ord(hintValue[idx-1])
133133

134-
queriesCount[0] += 1
135134
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, posValue))
136-
result = Request.queryPage(urlencode(forgedPayload))
135+
queriesCount[0] += 1
136+
result = Request.queryPage(urlencode(forgedPayload))
137137

138138
if result:
139139
return hintValue[idx-1]
@@ -155,6 +155,7 @@ def getChar(idx, charTbl=asciiTbl, sequentialOrder=True):
155155

156156
if len(charTbl) == 1:
157157
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, charTbl[0]))
158+
queriesCount[0] += 1
158159
result = Request.queryPage(urlencode(forgedPayload))
159160
if result:
160161
return chr(charTbl[0]) if charTbl[0] < 128 else unichr(charTbl[0])
@@ -165,9 +166,8 @@ def getChar(idx, charTbl=asciiTbl, sequentialOrder=True):
165166
minValue = charTbl[0]
166167

167168
while len(charTbl) != 1:
168-
queriesCount[0] += 1
169-
position = (len(charTbl) >> 1)
170-
posValue = charTbl[position]
169+
position = (len(charTbl) >> 1)
170+
posValue = charTbl[position]
171171

172172
if kb.dbms == "SQLite":
173173
posValueOld = posValue
@@ -181,7 +181,8 @@ def getChar(idx, charTbl=asciiTbl, sequentialOrder=True):
181181
else:
182182
forgedPayload = safeStringFormat(payload.replace('%3E', 'NOT BETWEEN 0 AND'), (expressionUnescaped, idx, posValue))
183183

184-
result = Request.queryPage(urlencode(forgedPayload))
184+
queriesCount[0] += 1
185+
result = Request.queryPage(urlencode(forgedPayload))
185186

186187
if kb.dbms == "SQLite":
187188
posValue = posValueOld
@@ -249,7 +250,7 @@ def downloadThread():
249250

250251
if conf.threadContinue:
251252
charStart = time.time()
252-
val = getChar(curidx)
253+
val = getChar(curidx)
253254

254255
if val is None:
255256
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
@@ -344,6 +345,7 @@ def downloadThread():
344345
raise
345346

346347
infoMsg = None
348+
347349
# If we have got one single character not correctly fetched it
348350
# can mean that the connection to the target url was lost
349351
if None in value:
@@ -369,32 +371,44 @@ def downloadThread():
369371
index = firstChar
370372

371373
while True:
372-
index += 1
374+
index += 1
373375
charStart = time.time()
374376

375-
#common prediction (a.k.a. good samaritan)
376-
if conf.useCommonPrediction:
377-
singleValue, predictedCharset, otherCharset = getGoodSamaritanParameters(kb.partRun, finalValue, asciiTbl)
377+
# Common prediction feature (a.k.a. "good samaritan")
378+
# NOTE: to be used only when multi-threading is not set for
379+
# the moment
380+
if conf.useCommonPrediction and len(finalValue) > 0 and kb.partRun is not None:
378381
val = None
382+
singleValue, commonCharset, otherCharset = goGoodSamaritan(kb.partRun, finalValue, asciiTbl)
379383

380-
#if there is no singleValue (single match from common-outputs.txt) use the returned predictedCharset
381-
if singleValue is None:
382-
val = getChar(index, predictedCharset, False) if predictedCharset else None
383-
else:
384-
#one shot query containing equals singleValue
384+
# If there is no singleValue (single match from
385+
# txt/common-outputs.txt) use the returned common
386+
# charset only to retrieve the query output
387+
if singleValue is not None:
388+
# One-shot query containing equals singleValue
385389
query = agent.prefixQuery(" %s" % safeStringFormat('AND (%s) = %s', (expressionUnescaped, unescaper.unescape('\'%s\'' % singleValue))))
386390
query = agent.postfixQuery(query)
391+
queriesCount[0] += 1
387392
result = Request.queryPage(urlencode(agent.payload(newValue=query)))
388-
#did we have luck?
393+
394+
# Did we have luck?
389395
if result:
390396
dataToSessionFile(replaceNewlineTabs(singleValue[index-1:]))
397+
391398
if showEta:
392-
etaProgressUpdate(time.time() - charStart, lastChar + 1)
399+
etaProgressUpdate(time.time() - charStart, len(singleValue))
393400
elif conf.verbose >= 1:
394401
dataToStdout(singleValue[index-1:])
402+
395403
finalValue = singleValue
404+
396405
break
397-
#if we had no luck with singleValue and predictedCharset use the returned otherCharset
406+
elif commonCharset:
407+
# TODO: this part does not seem to work yet
408+
val = getChar(index, commonCharset, False)
409+
410+
# If we had no luck with singleValue and common charset,
411+
# use the returned other charset
398412
if not val:
399413
val = getChar(index, otherCharset)
400414
else:

0 commit comments

Comments
 (0)