3838from lib .core .data import conf
3939from lib .core .data import kb
4040from lib .core .data import logger
41+ from lib .core .data import queries
4142from lib .core .exception import sqlmapConnectionException
4243from lib .core .exception import sqlmapValueException
4344from lib .core .exception import sqlmapThreadException
@@ -144,7 +145,12 @@ def tryHint(idx):
144145
145146 return None
146147
147- def getChar (idx , charTbl = asciiTbl , continuousOrder = True , expand = charsetType is None ): # continuousOrder means that distance between each two neighbour's numerical values is exactly 1
148+ def getChar (idx , charTbl = asciiTbl , continuousOrder = True , expand = charsetType is None ):
149+ """
150+ continuousOrder means that distance between each two neighbour's
151+ numerical values is exactly 1
152+ """
153+
148154 result = tryHint (idx )
149155
150156 if result :
@@ -153,7 +159,8 @@ def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is N
153159 if not continuousOrder :
154160 originalTbl = list (charTbl )
155161 else :
156- shiftTable = [5 , 4 ] # used for gradual expanding into unicode charspace
162+ # Used for gradual expanding into unicode charspace
163+ shiftTable = [5 , 4 ]
157164
158165 if len (charTbl ) == 1 :
159166 forgedPayload = safeStringFormat (payload .replace ('%3E' , '%3D' ), (expressionUnescaped , idx , charTbl [0 ]))
@@ -192,7 +199,8 @@ def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is N
192199
193200 if type (charTbl ) != xrange :
194201 charTbl = charTbl [position :]
195- else : # xrange - extended virtual charset used for memory/space optimization
202+ else :
203+ # xrange() - extended virtual charset used for memory/space optimization
196204 charTbl = xrange (charTbl [position ], charTbl [- 1 ] + 1 )
197205 else :
198206 maxValue = posValue
@@ -206,9 +214,14 @@ def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is N
206214 if continuousOrder :
207215 if maxValue == 1 :
208216 return None
209- elif minValue == maxChar : # going beyond the original charset
210- # if the original charTbl was [0,..,127] new one will be [128,..,128*16-1] or from 128 to 2047
211- # and instead of making a HUGE list with all elements we use here xrange, which is a virtual list
217+
218+ # Going beyond the original charset
219+ elif minValue == maxChar :
220+ # If the original charTbl was [0,..,127] new one
221+ # will be [128,..,128*16-1] or from 128 to 2047
222+ # and instead of making a HUGE list with all
223+ # elements we use here xrange, which is a virtual
224+ # list
212225 if expand and shiftTable :
213226 charTbl = xrange (maxChar + 1 , (maxChar + 1 ) << shiftTable .pop ())
214227 maxChar = maxValue = charTbl [- 1 ]
@@ -222,7 +235,10 @@ def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is N
222235 if minValue == maxChar or maxValue == minChar :
223236 return None
224237
225- for retVal in (originalTbl [originalTbl .index (minValue )], originalTbl [originalTbl .index (minValue ) + 1 ]): # if we are working with non-continuous set both minValue and character afterwards are possible candidates
238+ # If we are working with non-continuous elements, set
239+ # both minValue and character afterwards are possible
240+ # candidates
241+ for retVal in (originalTbl [originalTbl .index (minValue )], originalTbl [originalTbl .index (minValue ) + 1 ]):
226242 forgedPayload = safeStringFormat (payload .replace ('%3E' , '%3D' ), (expressionUnescaped , idx , retVal ))
227243 queriesCount [0 ] += 1
228244 result = Request .queryPage (urlencode (forgedPayload ))
@@ -244,6 +260,7 @@ def etaProgressUpdate(charTime, index):
244260 progress .update (index )
245261 progress .draw (eta )
246262
263+ # Go multi-threading (--threads > 1)
247264 if conf .threads > 1 and isinstance (length , int ) and length > 1 :
248265 value = [ None ] * length
249266 index = [ firstChar ] # As list for python nested function scoping
@@ -386,6 +403,8 @@ def downloadThread():
386403 dataToStdout (infoMsg )
387404
388405 conf .seqLock = None
406+
407+ # No multi-threading (--threads = 1)
389408 else :
390409 index = firstChar
391410
@@ -398,7 +417,7 @@ def downloadThread():
398417 # the moment
399418 if conf .useCommonPrediction and len (finalValue ) > 0 and kb .partRun is not None :
400419 val = None
401- singleValue , commonCharset , otherCharset = goGoodSamaritan (kb .partRun , finalValue , asciiTbl )
420+ singleValue , commonPatternValue , commonCharset , otherCharset = goGoodSamaritan (kb .partRun , finalValue , asciiTbl )
402421
403422 # If there is one single output in common-outputs, check
404423 # it via equal against the query output
@@ -422,10 +441,26 @@ def downloadThread():
422441
423442 break
424443
444+ # If there is a common pattern starting with finalValue,
445+ # check it via equal against the substring-query output
446+ if commonPatternValue is not None :
447+ # Substring-query containing equals commonPatternValue
448+ subquery = queries [kb .dbms ].substring % (expressionUnescaped , 1 , len (commonPatternValue ))
449+ query = agent .prefixQuery (" %s" % safeStringFormat ('AND (%s) = %s' , (subquery , unescaper .unescape ('\' %s\' ' % commonPatternValue ))))
450+ query = agent .postfixQuery (query )
451+ queriesCount [0 ] += 1
452+ result = Request .queryPage (urlencode (agent .payload (newValue = query )))
453+
454+ # Did we have luck?
455+ if result :
456+ val = commonPatternValue [index - 1 :]
457+ index += len (val )- 1
458+
425459 # Otherwise if there is no singleValue (single match from
426- # txt/common-outputs.txt) use the returned common
427- # charset only to retrieve the query output
428- if commonCharset :
460+ # txt/common-outputs.txt) and no commonPatternValue
461+ # (common pattern) use the returned common charset only
462+ # to retrieve the query output
463+ if not val and commonCharset :
429464 val = getChar (index , commonCharset , False )
430465
431466 # If we had no luck with singleValue and common charset,
0 commit comments