mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-01-24 00:04:23 +03:00
Code refactoring and minor bug fixes.
This commit is contained in:
parent
c431a74d9e
commit
9de1671b8f
|
@ -57,6 +57,7 @@ from lib.core.exception import sqlmapFilePathException
|
|||
from lib.core.exception import sqlmapNoneDataException
|
||||
from lib.core.exception import sqlmapMissingDependence
|
||||
from lib.core.exception import sqlmapSyntaxException
|
||||
from lib.core.optiondict import optDict
|
||||
from lib.core.settings import DESCRIPTION
|
||||
from lib.core.settings import IS_WIN
|
||||
from lib.core.settings import PLATFORM
|
||||
|
@ -417,7 +418,7 @@ def fileToStr(fileName):
|
|||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
filePointer = codecs.open(fileName, "r", conf.dataEncoding)
|
||||
filePointer = codecs.open(fileName, "rb", conf.dataEncoding)
|
||||
fileText = filePointer.read()
|
||||
|
||||
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
|
||||
|
@ -1106,7 +1107,8 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
|
|||
import gtk
|
||||
import pydot
|
||||
except ImportError, e:
|
||||
logger.error(e)
|
||||
errMsg = "profiling requires third-party libraries (%s)" % str(e)
|
||||
logger.error(errMsg)
|
||||
return
|
||||
|
||||
if profileOutputFile is None:
|
||||
|
@ -1209,6 +1211,9 @@ def initCommonOutputs():
|
|||
for line in cfile.xreadlines():
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
|
||||
if len(line) > 1:
|
||||
if line[0] == '[' and line[-1] == ']':
|
||||
key = line[1:-1]
|
||||
|
@ -1220,20 +1225,27 @@ def initCommonOutputs():
|
|||
|
||||
cfile.close()
|
||||
|
||||
def getGoodSamaritanParameters(part, prevValue, originalCharset):
|
||||
def goGoodSamaritan(part, prevValue, originalCharset):
|
||||
"""
|
||||
Function for retrieving parameters needed for good samaritan (common outputs) feature.
|
||||
Returns singleValue if there is a complete single match (in part of common-outputs.txt set by parameter 'part')
|
||||
regarding parameter prevValue. If there is no single value match, but multiple, predictedCharset is returned
|
||||
containing more probable characters (retrieved from matched items in common-outputs.txt) together with the
|
||||
rest of charset as otherCharset
|
||||
Function for retrieving parameters needed for common prediction (good
|
||||
samaritan) feature.
|
||||
|
||||
part is for instance Users, Databases, Tables and corresponds to the
|
||||
header (e.g. [Users]) in txt/common-outputs.txt.
|
||||
|
||||
prevValue: retrieved query output so far (e.g. 'i').
|
||||
|
||||
Returns singleValue if there is a complete single match (in part of
|
||||
txt/common-outputs.txt under 'part') regarding parameter prevValue. If
|
||||
there is no single value match, but multiple, commonCharset is
|
||||
returned containing more probable characters (retrieved from matched
|
||||
values in txt/common-outputs.txt) together with the rest of charset as
|
||||
otherCharset.
|
||||
"""
|
||||
|
||||
if kb.commonOutputs is None:
|
||||
initCommonOutputs()
|
||||
|
||||
if not part or not prevValue: #is not None and != ""
|
||||
return None, None, originalCharset
|
||||
|
||||
predictionSet = set()
|
||||
wildIndexes = []
|
||||
singleValue = None
|
||||
|
@ -1249,29 +1261,34 @@ def getGoodSamaritanParameters(part, prevValue, originalCharset):
|
|||
charIndex += 1
|
||||
findIndex = prevValue.find('.', charIndex)
|
||||
|
||||
# If the header we are looking for has common outputs defined
|
||||
if part in kb.commonOutputs:
|
||||
for item in kb.commonOutputs[part]:
|
||||
# Check if the common output (item) starts with prevValue
|
||||
if re.search('\A%s' % prevValue, item):
|
||||
singleValue = item
|
||||
|
||||
for index in wildIndexes:
|
||||
char = item[index]
|
||||
|
||||
if char not in predictionSet:
|
||||
predictionSet.add(char)
|
||||
|
||||
predictedCharset = []
|
||||
commonCharset = []
|
||||
otherCharset = []
|
||||
|
||||
# Split the original charset into common chars (commonCharset)
|
||||
# and other chars (otherCharset)
|
||||
for ordChar in originalCharset:
|
||||
if chr(ordChar) not in predictionSet:
|
||||
otherCharset.append(ordChar)
|
||||
else:
|
||||
predictedCharset.append(ordChar)
|
||||
commonCharset.append(ordChar)
|
||||
|
||||
predictedCharset.sort()
|
||||
commonCharset.sort()
|
||||
|
||||
if len(predictedCharset) > 1:
|
||||
return None, predictedCharset, otherCharset
|
||||
if len(commonCharset) > 1:
|
||||
return None, commonCharset, otherCharset
|
||||
else:
|
||||
return singleValue, None, originalCharset
|
||||
else:
|
||||
|
@ -1279,8 +1296,12 @@ def getGoodSamaritanParameters(part, prevValue, originalCharset):
|
|||
|
||||
def getCompiledRegex(regex, *args):
|
||||
"""
|
||||
Returns compiled regular expression and stores it in cache for further usage
|
||||
Returns compiled regular expression and stores it in cache for further
|
||||
usage
|
||||
"""
|
||||
|
||||
global __compiledRegularExpressions
|
||||
|
||||
if (regex, args) in __compiledRegularExpressions:
|
||||
return __compiledRegularExpressions[(regex, args)]
|
||||
else:
|
||||
|
@ -1290,15 +1311,23 @@ def getCompiledRegex(regex, *args):
|
|||
|
||||
def getPartRun():
|
||||
"""
|
||||
Goes through call stack and finds constructs matching conf.dmbsHandler.*. Returns it or it's alias used in common-outputs.txt
|
||||
Goes through call stack and finds constructs matching conf.dmbsHandler.*.
|
||||
Returns it or its alias used in txt/common-outputs.txt
|
||||
"""
|
||||
commonPartsDict = { "getTables":"Tables", "getColumns":"Columns", "getUsers":"Users", "getBanner":"Banners", "getDbs":"Databases" }
|
||||
|
||||
retVal = None
|
||||
commonPartsDict = optDict["Enumeration"]
|
||||
stack = [item[4][0] if isinstance(item[4], list) else '' for item in inspect.stack()]
|
||||
reobj = getCompiledRegex('conf\.dbmsHandler\.([^(]+)\(\)')
|
||||
|
||||
# Goes backwards through the stack to find the conf.dbmsHandler method
|
||||
# calling this function
|
||||
for i in xrange(len(stack) - 1, 0, -1):
|
||||
match = reobj.search(stack[i])
|
||||
|
||||
if match:
|
||||
# This is the calling conf.dbmsHandler method (e.g. 'getDbms')
|
||||
retVal = match.groups()[0]
|
||||
break
|
||||
return commonPartsDict[retVal] if retVal in commonPartsDict else retVal
|
||||
|
||||
return commonPartsDict[retVal][1] if retVal in commonPartsDict else retVal
|
||||
|
|
|
@ -23,7 +23,10 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
"""
|
||||
|
||||
optDict = {
|
||||
# Family: { "parameter_name": "parameter_datatype" },
|
||||
# Format:
|
||||
# Family: { "parameter name": "parameter datatype" },
|
||||
# Or:
|
||||
# Family: { "parameter name": ("parameter datatype", "category name used for common outputs feature") },
|
||||
"Target": {
|
||||
"direct": "string",
|
||||
"url": "string",
|
||||
|
@ -84,17 +87,17 @@ optDict = {
|
|||
},
|
||||
|
||||
"Enumeration": {
|
||||
"getBanner": "boolean",
|
||||
"getCurrentUser": "boolean",
|
||||
"getCurrentDb": "boolean",
|
||||
"getBanner": ("boolean", "Banners"),
|
||||
"getCurrentUser": ("boolean", "Users"),
|
||||
"getCurrentDb": ("boolean", "Databases"),
|
||||
"isDba": "boolean",
|
||||
"getUsers": "boolean",
|
||||
"getPasswordHashes": "boolean",
|
||||
"getPrivileges": "boolean",
|
||||
"getRoles": "boolean",
|
||||
"getDbs": "boolean",
|
||||
"getTables": "boolean",
|
||||
"getColumns": "boolean",
|
||||
"getUsers": ("boolean", "Users"),
|
||||
"getPasswordHashes": ("boolean", "Hashes"),
|
||||
"getPrivileges": ("boolean", "Privileges"),
|
||||
"getRoles": ("boolean", "Roles"),
|
||||
"getDbs": ("boolean", "Databases"),
|
||||
"getTables": ("boolean", "Tables"),
|
||||
"getColumns": ("boolean", "Columns"),
|
||||
"dumpTable": "boolean",
|
||||
"dumpAll": "boolean",
|
||||
"search": "boolean",
|
||||
|
@ -107,6 +110,8 @@ optDict = {
|
|||
"limitStop": "integer",
|
||||
"firstChar": "integer",
|
||||
"lastChar": "integer",
|
||||
"getNumOfTables": "integer",
|
||||
"getNumOfDBs": "integer",
|
||||
"query": "string",
|
||||
"sqlShell": "boolean"
|
||||
},
|
||||
|
@ -144,6 +149,7 @@ optDict = {
|
|||
},
|
||||
|
||||
"Miscellaneous": {
|
||||
"xmlFile": "string",
|
||||
"sessionFile": "string",
|
||||
"flushSession": "boolean",
|
||||
"eta": "boolean",
|
||||
|
|
|
@ -30,7 +30,7 @@ from lib.core.agent import agent
|
|||
from lib.core.common import dataToSessionFile
|
||||
from lib.core.common import dataToStdout
|
||||
from lib.core.common import getCharset
|
||||
from lib.core.common import getGoodSamaritanParameters
|
||||
from lib.core.common import goGoodSamaritan
|
||||
from lib.core.common import getPartRun
|
||||
from lib.core.common import replaceNewlineTabs
|
||||
from lib.core.common import safeStringFormat
|
||||
|
@ -53,11 +53,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
"""
|
||||
|
||||
partialValue = ""
|
||||
finalValue = ""
|
||||
|
||||
finalValue = ""
|
||||
asciiTbl = getCharset(charsetType)
|
||||
|
||||
kb.partRun = getPartRun() if conf.useCommonPrediction else None #set kb.partRun in case common-prediction used
|
||||
# Set kb.partRun in case "common prediction" feature (a.k.a. "good
|
||||
# samaritan") is used
|
||||
kb.partRun = getPartRun() if conf.useCommonPrediction else None
|
||||
|
||||
if "LENGTH(" in expression or "LEN(" in expression:
|
||||
firstChar = 0
|
||||
|
@ -116,9 +117,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
else:
|
||||
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
|
||||
|
||||
queriesCount = [0] # As list to deal with nested scoping rules
|
||||
|
||||
hintlock = threading.Lock()
|
||||
queriesCount = [0] # As list to deal with nested scoping rules
|
||||
hintlock = threading.Lock()
|
||||
|
||||
def tryHint(idx):
|
||||
hintlock.acquire()
|
||||
|
@ -131,9 +131,9 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
else:
|
||||
posValue = ord(hintValue[idx-1])
|
||||
|
||||
queriesCount[0] += 1
|
||||
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, posValue))
|
||||
result = Request.queryPage(urlencode(forgedPayload))
|
||||
queriesCount[0] += 1
|
||||
result = Request.queryPage(urlencode(forgedPayload))
|
||||
|
||||
if result:
|
||||
return hintValue[idx-1]
|
||||
|
@ -155,6 +155,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
|
||||
if len(charTbl) == 1:
|
||||
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, charTbl[0]))
|
||||
queriesCount[0] += 1
|
||||
result = Request.queryPage(urlencode(forgedPayload))
|
||||
if result:
|
||||
return chr(charTbl[0]) if charTbl[0] < 128 else unichr(charTbl[0])
|
||||
|
@ -165,9 +166,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
minValue = charTbl[0]
|
||||
|
||||
while len(charTbl) != 1:
|
||||
queriesCount[0] += 1
|
||||
position = (len(charTbl) >> 1)
|
||||
posValue = charTbl[position]
|
||||
position = (len(charTbl) >> 1)
|
||||
posValue = charTbl[position]
|
||||
|
||||
if kb.dbms == "SQLite":
|
||||
posValueOld = posValue
|
||||
|
@ -181,7 +181,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
else:
|
||||
forgedPayload = safeStringFormat(payload.replace('%3E', 'NOT BETWEEN 0 AND'), (expressionUnescaped, idx, posValue))
|
||||
|
||||
result = Request.queryPage(urlencode(forgedPayload))
|
||||
queriesCount[0] += 1
|
||||
result = Request.queryPage(urlencode(forgedPayload))
|
||||
|
||||
if kb.dbms == "SQLite":
|
||||
posValue = posValueOld
|
||||
|
@ -249,7 +250,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
|
||||
if conf.threadContinue:
|
||||
charStart = time.time()
|
||||
val = getChar(curidx)
|
||||
val = getChar(curidx)
|
||||
|
||||
if val is None:
|
||||
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
|
||||
|
@ -344,6 +345,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
raise
|
||||
|
||||
infoMsg = None
|
||||
|
||||
# If we have got one single character not correctly fetched it
|
||||
# can mean that the connection to the target url was lost
|
||||
if None in value:
|
||||
|
@ -369,32 +371,44 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
|||
index = firstChar
|
||||
|
||||
while True:
|
||||
index += 1
|
||||
index += 1
|
||||
charStart = time.time()
|
||||
|
||||
#common prediction (a.k.a. good samaritan)
|
||||
if conf.useCommonPrediction:
|
||||
singleValue, predictedCharset, otherCharset = getGoodSamaritanParameters(kb.partRun, finalValue, asciiTbl)
|
||||
# Common prediction feature (a.k.a. "good samaritan")
|
||||
# NOTE: to be used only when multi-threading is not set for
|
||||
# the moment
|
||||
if conf.useCommonPrediction and len(finalValue) > 0 and kb.partRun is not None:
|
||||
val = None
|
||||
singleValue, commonCharset, otherCharset = goGoodSamaritan(kb.partRun, finalValue, asciiTbl)
|
||||
|
||||
#if there is no singleValue (single match from common-outputs.txt) use the returned predictedCharset
|
||||
if singleValue is None:
|
||||
val = getChar(index, predictedCharset, False) if predictedCharset else None
|
||||
else:
|
||||
#one shot query containing equals singleValue
|
||||
# If there is no singleValue (single match from
|
||||
# txt/common-outputs.txt) use the returned common
|
||||
# charset only to retrieve the query output
|
||||
if singleValue is not None:
|
||||
# One-shot query containing equals singleValue
|
||||
query = agent.prefixQuery(" %s" % safeStringFormat('AND (%s) = %s', (expressionUnescaped, unescaper.unescape('\'%s\'' % singleValue))))
|
||||
query = agent.postfixQuery(query)
|
||||
queriesCount[0] += 1
|
||||
result = Request.queryPage(urlencode(agent.payload(newValue=query)))
|
||||
#did we have luck?
|
||||
|
||||
# Did we have luck?
|
||||
if result:
|
||||
dataToSessionFile(replaceNewlineTabs(singleValue[index-1:]))
|
||||
|
||||
if showEta:
|
||||
etaProgressUpdate(time.time() - charStart, lastChar + 1)
|
||||
etaProgressUpdate(time.time() - charStart, len(singleValue))
|
||||
elif conf.verbose >= 1:
|
||||
dataToStdout(singleValue[index-1:])
|
||||
|
||||
finalValue = singleValue
|
||||
|
||||
break
|
||||
#if we had no luck with singleValue and predictedCharset use the returned otherCharset
|
||||
elif commonCharset:
|
||||
# TODO: this part does not seem to work yet
|
||||
val = getChar(index, commonCharset, False)
|
||||
|
||||
# If we had no luck with singleValue and common charset,
|
||||
# use the returned other charset
|
||||
if not val:
|
||||
val = getChar(index, otherCharset)
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue
Block a user