mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-02-03 13:14:13 +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 sqlmapNoneDataException
|
||||||
from lib.core.exception import sqlmapMissingDependence
|
from lib.core.exception import sqlmapMissingDependence
|
||||||
from lib.core.exception import sqlmapSyntaxException
|
from lib.core.exception import sqlmapSyntaxException
|
||||||
|
from lib.core.optiondict import optDict
|
||||||
from lib.core.settings import DESCRIPTION
|
from lib.core.settings import DESCRIPTION
|
||||||
from lib.core.settings import IS_WIN
|
from lib.core.settings import IS_WIN
|
||||||
from lib.core.settings import PLATFORM
|
from lib.core.settings import PLATFORM
|
||||||
|
@ -417,7 +418,7 @@ def fileToStr(fileName):
|
||||||
@rtype: C{str}
|
@rtype: C{str}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
filePointer = codecs.open(fileName, "r", conf.dataEncoding)
|
filePointer = codecs.open(fileName, "rb", conf.dataEncoding)
|
||||||
fileText = filePointer.read()
|
fileText = filePointer.read()
|
||||||
|
|
||||||
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
|
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
|
||||||
|
@ -1106,7 +1107,8 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None):
|
||||||
import gtk
|
import gtk
|
||||||
import pydot
|
import pydot
|
||||||
except ImportError, e:
|
except ImportError, e:
|
||||||
logger.error(e)
|
errMsg = "profiling requires third-party libraries (%s)" % str(e)
|
||||||
|
logger.error(errMsg)
|
||||||
return
|
return
|
||||||
|
|
||||||
if profileOutputFile is None:
|
if profileOutputFile is None:
|
||||||
|
@ -1209,6 +1211,9 @@ def initCommonOutputs():
|
||||||
for line in cfile.xreadlines():
|
for line in cfile.xreadlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
|
||||||
|
if line.startswith('#'):
|
||||||
|
continue
|
||||||
|
|
||||||
if len(line) > 1:
|
if len(line) > 1:
|
||||||
if line[0] == '[' and line[-1] == ']':
|
if line[0] == '[' and line[-1] == ']':
|
||||||
key = line[1:-1]
|
key = line[1:-1]
|
||||||
|
@ -1220,20 +1225,27 @@ def initCommonOutputs():
|
||||||
|
|
||||||
cfile.close()
|
cfile.close()
|
||||||
|
|
||||||
def getGoodSamaritanParameters(part, prevValue, originalCharset):
|
def goGoodSamaritan(part, prevValue, originalCharset):
|
||||||
"""
|
"""
|
||||||
Function for retrieving parameters needed for good samaritan (common outputs) feature.
|
Function for retrieving parameters needed for common prediction (good
|
||||||
Returns singleValue if there is a complete single match (in part of common-outputs.txt set by parameter 'part')
|
samaritan) feature.
|
||||||
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
|
part is for instance Users, Databases, Tables and corresponds to the
|
||||||
rest of charset as otherCharset
|
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:
|
if kb.commonOutputs is None:
|
||||||
initCommonOutputs()
|
initCommonOutputs()
|
||||||
|
|
||||||
if not part or not prevValue: #is not None and != ""
|
|
||||||
return None, None, originalCharset
|
|
||||||
|
|
||||||
predictionSet = set()
|
predictionSet = set()
|
||||||
wildIndexes = []
|
wildIndexes = []
|
||||||
singleValue = None
|
singleValue = None
|
||||||
|
@ -1249,29 +1261,34 @@ def getGoodSamaritanParameters(part, prevValue, originalCharset):
|
||||||
charIndex += 1
|
charIndex += 1
|
||||||
findIndex = prevValue.find('.', charIndex)
|
findIndex = prevValue.find('.', charIndex)
|
||||||
|
|
||||||
|
# If the header we are looking for has common outputs defined
|
||||||
if part in kb.commonOutputs:
|
if part in kb.commonOutputs:
|
||||||
for item in kb.commonOutputs[part]:
|
for item in kb.commonOutputs[part]:
|
||||||
|
# Check if the common output (item) starts with prevValue
|
||||||
if re.search('\A%s' % prevValue, item):
|
if re.search('\A%s' % prevValue, item):
|
||||||
singleValue = item
|
singleValue = item
|
||||||
|
|
||||||
for index in wildIndexes:
|
for index in wildIndexes:
|
||||||
char = item[index]
|
char = item[index]
|
||||||
|
|
||||||
if char not in predictionSet:
|
if char not in predictionSet:
|
||||||
predictionSet.add(char)
|
predictionSet.add(char)
|
||||||
|
|
||||||
predictedCharset = []
|
commonCharset = []
|
||||||
otherCharset = []
|
otherCharset = []
|
||||||
|
|
||||||
|
# Split the original charset into common chars (commonCharset)
|
||||||
|
# and other chars (otherCharset)
|
||||||
for ordChar in originalCharset:
|
for ordChar in originalCharset:
|
||||||
if chr(ordChar) not in predictionSet:
|
if chr(ordChar) not in predictionSet:
|
||||||
otherCharset.append(ordChar)
|
otherCharset.append(ordChar)
|
||||||
else:
|
else:
|
||||||
predictedCharset.append(ordChar)
|
commonCharset.append(ordChar)
|
||||||
|
|
||||||
predictedCharset.sort()
|
commonCharset.sort()
|
||||||
|
|
||||||
if len(predictedCharset) > 1:
|
if len(commonCharset) > 1:
|
||||||
return None, predictedCharset, otherCharset
|
return None, commonCharset, otherCharset
|
||||||
else:
|
else:
|
||||||
return singleValue, None, originalCharset
|
return singleValue, None, originalCharset
|
||||||
else:
|
else:
|
||||||
|
@ -1279,8 +1296,12 @@ def getGoodSamaritanParameters(part, prevValue, originalCharset):
|
||||||
|
|
||||||
def getCompiledRegex(regex, *args):
|
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:
|
if (regex, args) in __compiledRegularExpressions:
|
||||||
return __compiledRegularExpressions[(regex, args)]
|
return __compiledRegularExpressions[(regex, args)]
|
||||||
else:
|
else:
|
||||||
|
@ -1290,15 +1311,23 @@ def getCompiledRegex(regex, *args):
|
||||||
|
|
||||||
def getPartRun():
|
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
|
retVal = None
|
||||||
|
commonPartsDict = optDict["Enumeration"]
|
||||||
stack = [item[4][0] if isinstance(item[4], list) else '' for item in inspect.stack()]
|
stack = [item[4][0] if isinstance(item[4], list) else '' for item in inspect.stack()]
|
||||||
reobj = getCompiledRegex('conf\.dbmsHandler\.([^(]+)\(\)')
|
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):
|
for i in xrange(len(stack) - 1, 0, -1):
|
||||||
match = reobj.search(stack[i])
|
match = reobj.search(stack[i])
|
||||||
|
|
||||||
if match:
|
if match:
|
||||||
|
# This is the calling conf.dbmsHandler method (e.g. 'getDbms')
|
||||||
retVal = match.groups()[0]
|
retVal = match.groups()[0]
|
||||||
break
|
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 = {
|
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": {
|
"Target": {
|
||||||
"direct": "string",
|
"direct": "string",
|
||||||
"url": "string",
|
"url": "string",
|
||||||
|
@ -84,17 +87,17 @@ optDict = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"Enumeration": {
|
"Enumeration": {
|
||||||
"getBanner": "boolean",
|
"getBanner": ("boolean", "Banners"),
|
||||||
"getCurrentUser": "boolean",
|
"getCurrentUser": ("boolean", "Users"),
|
||||||
"getCurrentDb": "boolean",
|
"getCurrentDb": ("boolean", "Databases"),
|
||||||
"isDba": "boolean",
|
"isDba": "boolean",
|
||||||
"getUsers": "boolean",
|
"getUsers": ("boolean", "Users"),
|
||||||
"getPasswordHashes": "boolean",
|
"getPasswordHashes": ("boolean", "Hashes"),
|
||||||
"getPrivileges": "boolean",
|
"getPrivileges": ("boolean", "Privileges"),
|
||||||
"getRoles": "boolean",
|
"getRoles": ("boolean", "Roles"),
|
||||||
"getDbs": "boolean",
|
"getDbs": ("boolean", "Databases"),
|
||||||
"getTables": "boolean",
|
"getTables": ("boolean", "Tables"),
|
||||||
"getColumns": "boolean",
|
"getColumns": ("boolean", "Columns"),
|
||||||
"dumpTable": "boolean",
|
"dumpTable": "boolean",
|
||||||
"dumpAll": "boolean",
|
"dumpAll": "boolean",
|
||||||
"search": "boolean",
|
"search": "boolean",
|
||||||
|
@ -107,6 +110,8 @@ optDict = {
|
||||||
"limitStop": "integer",
|
"limitStop": "integer",
|
||||||
"firstChar": "integer",
|
"firstChar": "integer",
|
||||||
"lastChar": "integer",
|
"lastChar": "integer",
|
||||||
|
"getNumOfTables": "integer",
|
||||||
|
"getNumOfDBs": "integer",
|
||||||
"query": "string",
|
"query": "string",
|
||||||
"sqlShell": "boolean"
|
"sqlShell": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -144,6 +149,7 @@ optDict = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"Miscellaneous": {
|
"Miscellaneous": {
|
||||||
|
"xmlFile": "string",
|
||||||
"sessionFile": "string",
|
"sessionFile": "string",
|
||||||
"flushSession": "boolean",
|
"flushSession": "boolean",
|
||||||
"eta": "boolean",
|
"eta": "boolean",
|
||||||
|
|
|
@ -30,7 +30,7 @@ from lib.core.agent import agent
|
||||||
from lib.core.common import dataToSessionFile
|
from lib.core.common import dataToSessionFile
|
||||||
from lib.core.common import dataToStdout
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.common import getCharset
|
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 getPartRun
|
||||||
from lib.core.common import replaceNewlineTabs
|
from lib.core.common import replaceNewlineTabs
|
||||||
from lib.core.common import safeStringFormat
|
from lib.core.common import safeStringFormat
|
||||||
|
@ -54,10 +54,11 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
|
|
||||||
partialValue = ""
|
partialValue = ""
|
||||||
finalValue = ""
|
finalValue = ""
|
||||||
|
|
||||||
asciiTbl = getCharset(charsetType)
|
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:
|
if "LENGTH(" in expression or "LEN(" in expression:
|
||||||
firstChar = 0
|
firstChar = 0
|
||||||
|
@ -117,7 +118,6 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
|
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
|
||||||
|
|
||||||
queriesCount = [0] # As list to deal with nested scoping rules
|
queriesCount = [0] # As list to deal with nested scoping rules
|
||||||
|
|
||||||
hintlock = threading.Lock()
|
hintlock = threading.Lock()
|
||||||
|
|
||||||
def tryHint(idx):
|
def tryHint(idx):
|
||||||
|
@ -131,8 +131,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
else:
|
else:
|
||||||
posValue = ord(hintValue[idx-1])
|
posValue = ord(hintValue[idx-1])
|
||||||
|
|
||||||
queriesCount[0] += 1
|
|
||||||
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, posValue))
|
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, posValue))
|
||||||
|
queriesCount[0] += 1
|
||||||
result = Request.queryPage(urlencode(forgedPayload))
|
result = Request.queryPage(urlencode(forgedPayload))
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
|
@ -155,6 +155,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
|
|
||||||
if len(charTbl) == 1:
|
if len(charTbl) == 1:
|
||||||
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, charTbl[0]))
|
forgedPayload = safeStringFormat(payload.replace('%3E', '%3D'), (expressionUnescaped, idx, charTbl[0]))
|
||||||
|
queriesCount[0] += 1
|
||||||
result = Request.queryPage(urlencode(forgedPayload))
|
result = Request.queryPage(urlencode(forgedPayload))
|
||||||
if result:
|
if result:
|
||||||
return chr(charTbl[0]) if charTbl[0] < 128 else unichr(charTbl[0])
|
return chr(charTbl[0]) if charTbl[0] < 128 else unichr(charTbl[0])
|
||||||
|
@ -165,7 +166,6 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
minValue = charTbl[0]
|
minValue = charTbl[0]
|
||||||
|
|
||||||
while len(charTbl) != 1:
|
while len(charTbl) != 1:
|
||||||
queriesCount[0] += 1
|
|
||||||
position = (len(charTbl) >> 1)
|
position = (len(charTbl) >> 1)
|
||||||
posValue = charTbl[position]
|
posValue = charTbl[position]
|
||||||
|
|
||||||
|
@ -181,6 +181,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
else:
|
else:
|
||||||
forgedPayload = safeStringFormat(payload.replace('%3E', 'NOT BETWEEN 0 AND'), (expressionUnescaped, idx, posValue))
|
forgedPayload = safeStringFormat(payload.replace('%3E', 'NOT BETWEEN 0 AND'), (expressionUnescaped, idx, posValue))
|
||||||
|
|
||||||
|
queriesCount[0] += 1
|
||||||
result = Request.queryPage(urlencode(forgedPayload))
|
result = Request.queryPage(urlencode(forgedPayload))
|
||||||
|
|
||||||
if kb.dbms == "SQLite":
|
if kb.dbms == "SQLite":
|
||||||
|
@ -344,6 +345,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
raise
|
raise
|
||||||
|
|
||||||
infoMsg = None
|
infoMsg = None
|
||||||
|
|
||||||
# If we have got one single character not correctly fetched it
|
# If we have got one single character not correctly fetched it
|
||||||
# can mean that the connection to the target url was lost
|
# can mean that the connection to the target url was lost
|
||||||
if None in value:
|
if None in value:
|
||||||
|
@ -372,29 +374,41 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||||
index += 1
|
index += 1
|
||||||
charStart = time.time()
|
charStart = time.time()
|
||||||
|
|
||||||
#common prediction (a.k.a. good samaritan)
|
# Common prediction feature (a.k.a. "good samaritan")
|
||||||
if conf.useCommonPrediction:
|
# NOTE: to be used only when multi-threading is not set for
|
||||||
singleValue, predictedCharset, otherCharset = getGoodSamaritanParameters(kb.partRun, finalValue, asciiTbl)
|
# the moment
|
||||||
|
if conf.useCommonPrediction and len(finalValue) > 0 and kb.partRun is not None:
|
||||||
val = 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 there is no singleValue (single match from
|
||||||
if singleValue is None:
|
# txt/common-outputs.txt) use the returned common
|
||||||
val = getChar(index, predictedCharset, False) if predictedCharset else None
|
# charset only to retrieve the query output
|
||||||
else:
|
if singleValue is not None:
|
||||||
#one shot query containing equals singleValue
|
# One-shot query containing equals singleValue
|
||||||
query = agent.prefixQuery(" %s" % safeStringFormat('AND (%s) = %s', (expressionUnescaped, unescaper.unescape('\'%s\'' % singleValue))))
|
query = agent.prefixQuery(" %s" % safeStringFormat('AND (%s) = %s', (expressionUnescaped, unescaper.unescape('\'%s\'' % singleValue))))
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
|
queriesCount[0] += 1
|
||||||
result = Request.queryPage(urlencode(agent.payload(newValue=query)))
|
result = Request.queryPage(urlencode(agent.payload(newValue=query)))
|
||||||
#did we have luck?
|
|
||||||
|
# Did we have luck?
|
||||||
if result:
|
if result:
|
||||||
dataToSessionFile(replaceNewlineTabs(singleValue[index-1:]))
|
dataToSessionFile(replaceNewlineTabs(singleValue[index-1:]))
|
||||||
|
|
||||||
if showEta:
|
if showEta:
|
||||||
etaProgressUpdate(time.time() - charStart, lastChar + 1)
|
etaProgressUpdate(time.time() - charStart, len(singleValue))
|
||||||
elif conf.verbose >= 1:
|
elif conf.verbose >= 1:
|
||||||
dataToStdout(singleValue[index-1:])
|
dataToStdout(singleValue[index-1:])
|
||||||
|
|
||||||
finalValue = singleValue
|
finalValue = singleValue
|
||||||
|
|
||||||
break
|
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:
|
if not val:
|
||||||
val = getChar(index, otherCharset)
|
val = getChar(index, otherCharset)
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user