mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-06 12:41:30 +00:00
sqlmap 0.8-rc3: Merge from Miroslav Stampar's branch fixing a bug when verbosity > 2, another major bug with urlencoding/urldecoding of POST data and Cookies, adding --drop-set-cookie option, implementing support to automatically decode gzip and deflate HTTP responses, support for Google dork page result (--gpage) and a minor code cleanup.
This commit is contained in:
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
@@ -32,10 +30,7 @@ import string
|
||||
import sys
|
||||
import time
|
||||
import urlparse
|
||||
|
||||
|
||||
from lib.contrib import magic
|
||||
from lib.core.convert import urldecode
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
@@ -115,7 +110,6 @@ def paramToDict(place, parameters=None):
|
||||
|
||||
return testableParameters
|
||||
|
||||
|
||||
def formatDBMSfp(versions=None):
|
||||
"""
|
||||
This function format the back-end DBMS fingerprint value and return its
|
||||
@@ -139,13 +133,11 @@ def formatDBMSfp(versions=None):
|
||||
|
||||
return kb.dbms
|
||||
|
||||
|
||||
def formatFingerprintString(values, chain=" or "):
|
||||
strJoin = "|".join([v for v in values])
|
||||
|
||||
return strJoin.replace("|", chain)
|
||||
|
||||
|
||||
def formatFingerprint(target, info):
|
||||
"""
|
||||
This function format the back-end operating system fingerprint value
|
||||
@@ -198,7 +190,6 @@ def formatFingerprint(target, info):
|
||||
|
||||
return infoStr
|
||||
|
||||
|
||||
def getHtmlErrorFp():
|
||||
"""
|
||||
This function parses the knowledge base htmlFp list and return its
|
||||
@@ -222,7 +213,6 @@ def getHtmlErrorFp():
|
||||
|
||||
return htmlParsed
|
||||
|
||||
|
||||
def getDocRoot():
|
||||
docRoot = None
|
||||
pagePath = os.path.dirname(conf.path)
|
||||
@@ -236,7 +226,7 @@ def getDocRoot():
|
||||
for absFilePath in kb.absFilePaths:
|
||||
absFilePathWin = None
|
||||
|
||||
if re.search("([\w]\:[\/\\\\]+)", absFilePath):
|
||||
if re.search("[A-Za-z]:(\\[\w.\\]*)?", absFilePath):
|
||||
absFilePathWin = absFilePath
|
||||
absFilePath = absFilePath[2:].replace("\\", "/")
|
||||
|
||||
@@ -269,7 +259,6 @@ def getDocRoot():
|
||||
|
||||
return docRoot
|
||||
|
||||
|
||||
def getDirs():
|
||||
directories = set()
|
||||
|
||||
@@ -305,33 +294,28 @@ def getDirs():
|
||||
directories.add(defaultDir)
|
||||
|
||||
return directories
|
||||
|
||||
|
||||
|
||||
def filePathToString(filePath):
|
||||
strRepl = filePath.replace("/", "_").replace("\\", "_")
|
||||
strRepl = strRepl.replace(" ", "_").replace(":", "_")
|
||||
|
||||
return strRepl
|
||||
|
||||
|
||||
def dataToStdout(data):
|
||||
sys.stdout.write(data)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
|
||||
def dataToSessionFile(data):
|
||||
if not conf.sessionFile:
|
||||
return
|
||||
|
||||
conf.sessionFP.write(data)
|
||||
conf.sessionFP.flush()
|
||||
|
||||
|
||||
|
||||
def dataToDumpFile(dumpFile, data):
|
||||
dumpFile.write(data)
|
||||
dumpFile.flush()
|
||||
|
||||
|
||||
|
||||
def dataToOutFile(data):
|
||||
if not data:
|
||||
return "No data retrieved"
|
||||
@@ -346,7 +330,6 @@ def dataToOutFile(data):
|
||||
|
||||
return rFilePath
|
||||
|
||||
|
||||
def strToHex(inpStr):
|
||||
"""
|
||||
@param inpStr: inpStr to be converted into its hexadecimal value.
|
||||
@@ -369,8 +352,7 @@ def strToHex(inpStr):
|
||||
hexStr += hexChar
|
||||
|
||||
return hexStr
|
||||
|
||||
|
||||
|
||||
def fileToStr(fileName):
|
||||
"""
|
||||
@param fileName: file path to read the content and return as a no
|
||||
@@ -384,13 +366,7 @@ def fileToStr(fileName):
|
||||
filePointer = open(fileName, "r")
|
||||
fileText = filePointer.read()
|
||||
|
||||
fileText = fileText.replace(" ", "")
|
||||
fileText = fileText.replace("\t", "")
|
||||
fileText = fileText.replace("\r", "")
|
||||
fileText = fileText.replace("\n", " ")
|
||||
|
||||
return fileText
|
||||
|
||||
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
|
||||
|
||||
def fileToHex(fileName):
|
||||
"""
|
||||
@@ -407,7 +383,6 @@ def fileToHex(fileName):
|
||||
|
||||
return hexFile
|
||||
|
||||
|
||||
def readInput(message, default=None):
|
||||
"""
|
||||
@param message: message to display on terminal.
|
||||
@@ -435,8 +410,7 @@ def readInput(message, default=None):
|
||||
data = default
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
def randomRange(start=0, stop=1000):
|
||||
"""
|
||||
@param start: starting number.
|
||||
@@ -451,7 +425,6 @@ def randomRange(start=0, stop=1000):
|
||||
|
||||
return int(random.randint(start, stop))
|
||||
|
||||
|
||||
def randomInt(length=4):
|
||||
"""
|
||||
@param length: length of the random string.
|
||||
@@ -463,7 +436,6 @@ def randomInt(length=4):
|
||||
|
||||
return int("".join([random.choice(string.digits) for _ in xrange(0, length)]))
|
||||
|
||||
|
||||
def randomStr(length=5, lowercase=False):
|
||||
"""
|
||||
@param length: length of the random string.
|
||||
@@ -473,14 +445,13 @@ def randomStr(length=5, lowercase=False):
|
||||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
if lowercase == True:
|
||||
if lowercase:
|
||||
rndStr = "".join([random.choice(string.lowercase) for _ in xrange(0, length)])
|
||||
else:
|
||||
rndStr = "".join([random.choice(string.letters) for _ in xrange(0, length)])
|
||||
|
||||
return rndStr
|
||||
|
||||
|
||||
|
||||
def sanitizeStr(inpStr):
|
||||
"""
|
||||
@param inpStr: inpStr to sanitize: cast to str datatype and replace
|
||||
@@ -496,7 +467,6 @@ def sanitizeStr(inpStr):
|
||||
|
||||
return cleanString
|
||||
|
||||
|
||||
def checkFile(filename):
|
||||
"""
|
||||
@param filename: filename to check if it exists.
|
||||
@@ -505,15 +475,13 @@ def checkFile(filename):
|
||||
|
||||
if not os.path.exists(filename):
|
||||
raise sqlmapFilePathException, "unable to read file '%s'" % filename
|
||||
|
||||
|
||||
|
||||
def replaceNewlineTabs(inpStr):
|
||||
replacedString = inpStr.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
|
||||
replacedString = replacedString.replace(temp.delimiter, "__DEL__")
|
||||
|
||||
return replacedString
|
||||
|
||||
|
||||
def banner():
|
||||
"""
|
||||
This function prints sqlmap banner with its version
|
||||
@@ -523,8 +491,7 @@ def banner():
|
||||
%s
|
||||
by Bernardo Damele A. G. <bernardo.damele@gmail.com>
|
||||
""" % VERSION_STRING
|
||||
|
||||
|
||||
|
||||
def parsePasswordHash(password):
|
||||
blank = " " * 8
|
||||
|
||||
@@ -542,8 +509,7 @@ def parsePasswordHash(password):
|
||||
password += "%suppercase: %s" % (blank, hexPassword[54:])
|
||||
|
||||
return password
|
||||
|
||||
|
||||
|
||||
def cleanQuery(query):
|
||||
upperQuery = query
|
||||
|
||||
@@ -556,8 +522,7 @@ def cleanQuery(query):
|
||||
upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
|
||||
|
||||
return upperQuery
|
||||
|
||||
|
||||
|
||||
def setPaths():
|
||||
# sqlmap paths
|
||||
paths.SQLMAP_CONTRIB_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "contrib")
|
||||
@@ -581,8 +546,7 @@ def setPaths():
|
||||
paths.MYSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mysql.xml")
|
||||
paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml")
|
||||
paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml")
|
||||
|
||||
|
||||
|
||||
def weAreFrozen():
|
||||
"""
|
||||
Returns whether we are frozen via py2exe.
|
||||
@@ -592,7 +556,6 @@ def weAreFrozen():
|
||||
|
||||
return hasattr(sys, "frozen")
|
||||
|
||||
|
||||
def parseTargetUrl():
|
||||
"""
|
||||
Parse target url and set some attributes into the configuration
|
||||
@@ -623,11 +586,10 @@ def parseTargetUrl():
|
||||
conf.port = 80
|
||||
|
||||
if __urlSplit[3]:
|
||||
conf.parameters["GET"] = urldecode(__urlSplit[3]).replace("%", "%%")
|
||||
conf.parameters["GET"] = __urlSplit[3]
|
||||
|
||||
conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path)
|
||||
|
||||
|
||||
|
||||
def expandAsteriskForColumns(expression):
|
||||
# If the user provided an asterisk rather than the column(s)
|
||||
# name, sqlmap will retrieve the columns itself and reprocess
|
||||
@@ -659,8 +621,7 @@ def expandAsteriskForColumns(expression):
|
||||
logger.info(infoMsg)
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
|
||||
def getRange(count, dump=False, plusOne=False):
|
||||
count = int(count)
|
||||
indexRange = None
|
||||
@@ -674,14 +635,13 @@ def getRange(count, dump=False, plusOne=False):
|
||||
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
|
||||
limitStart = conf.limitStart
|
||||
|
||||
if kb.dbms == "Oracle" or plusOne == True:
|
||||
if kb.dbms == "Oracle" or plusOne:
|
||||
indexRange = range(limitStart, limitStop + 1)
|
||||
else:
|
||||
indexRange = range(limitStart - 1, limitStop)
|
||||
|
||||
return indexRange
|
||||
|
||||
|
||||
|
||||
def parseUnionPage(output, expression, partial=False, condition=None, sort=True):
|
||||
data = []
|
||||
|
||||
@@ -696,7 +656,7 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
|
||||
|
||||
output = re.findall(regExpr, output, re.S)
|
||||
|
||||
if condition == None:
|
||||
if condition is None:
|
||||
condition = (
|
||||
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
|
||||
and expression in kb.resumedQueries[conf.url].keys()
|
||||
@@ -731,27 +691,25 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
|
||||
data = data[0]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
def getDelayQuery():
|
||||
query = None
|
||||
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
if kb.dbms in ("MySQL", "PostgreSQL"):
|
||||
if not kb.data.banner:
|
||||
conf.dbmsHandler.getVersionFromBanner()
|
||||
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
|
||||
if ( kb.dbms == "MySQL" and banVer >= "5.0.12" ) or ( kb.dbms == "PostgreSQL" and banVer >= "8.2" ):
|
||||
if (kb.dbms == "MySQL" and banVer >= "5.0.12") or (kb.dbms == "PostgreSQL" and banVer >= "8.2"):
|
||||
query = queries[kb.dbms].timedelay % conf.timeSec
|
||||
else:
|
||||
query = queries[kb.dbms].timedelay2 % conf.timeSec
|
||||
else:
|
||||
else:
|
||||
query = queries[kb.dbms].timedelay % conf.timeSec
|
||||
|
||||
return query
|
||||
|
||||
|
||||
|
||||
def getLocalIP():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((conf.hostname, conf.port))
|
||||
@@ -760,11 +718,9 @@ def getLocalIP():
|
||||
|
||||
return ip
|
||||
|
||||
|
||||
def getRemoteIP():
|
||||
return socket.gethostbyname(conf.hostname)
|
||||
|
||||
|
||||
def getFileType(filePath):
|
||||
try:
|
||||
magicFileType = magic.from_file(filePath)
|
||||
@@ -775,8 +731,7 @@ def getFileType(filePath):
|
||||
return "text"
|
||||
else:
|
||||
return "binary"
|
||||
|
||||
|
||||
|
||||
def pollProcess(process):
|
||||
while True:
|
||||
dataToStdout(".")
|
||||
@@ -793,12 +748,11 @@ def pollProcess(process):
|
||||
dataToStdout(" quit unexpectedly with return code %d\n" % returncode)
|
||||
|
||||
break
|
||||
|
||||
|
||||
|
||||
def getCharset(charsetType=None):
|
||||
asciiTbl = []
|
||||
|
||||
if charsetType == None:
|
||||
if charsetType is None:
|
||||
asciiTbl = range(0, 128)
|
||||
|
||||
# 0 or 1
|
||||
@@ -832,22 +786,49 @@ def getCharset(charsetType=None):
|
||||
asciiTbl.extend(range(96, 123))
|
||||
|
||||
return asciiTbl
|
||||
|
||||
|
||||
|
||||
def searchEnvPath(fileName):
|
||||
envPaths = os.environ["PATH"]
|
||||
result = None
|
||||
result = None
|
||||
|
||||
if IS_WIN is True:
|
||||
if IS_WIN:
|
||||
envPaths = envPaths.split(";")
|
||||
else:
|
||||
envPaths = envPaths.split(":")
|
||||
|
||||
for envPath in envPaths:
|
||||
envPath = envPath.replace(";", "")
|
||||
result = os.path.exists(os.path.normpath(os.path.join(envPath, fileName)))
|
||||
result = os.path.exists(os.path.normpath(os.path.join(envPath, fileName)))
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
def sanitizeCookie(cookieStr, warn=False):
|
||||
if cookieStr:
|
||||
result = ""
|
||||
changed = False
|
||||
for part in cookieStr.split(';'):
|
||||
index = part.find('=') + 1
|
||||
if index > 0:
|
||||
name = part[:index - 1].strip()
|
||||
value = part[index:].replace(",","%2C").replace(";","%3B").replace(" ","%20")
|
||||
if value != part[index:]:
|
||||
changed = True
|
||||
result += ";%s=%s" % (name, value)
|
||||
elif part.strip().lower() != "secure":
|
||||
result += "%s%s" % ("%3B", part.replace(",","%2C").replace(";","%3B").replace(" ","%20"))
|
||||
else:
|
||||
result += ";secure"
|
||||
if result.startswith(';'):
|
||||
result = result[1:]
|
||||
elif result.startswith('%3B'):
|
||||
result = result[3:]
|
||||
if changed and warn:
|
||||
warnMsg = "cookie is provided in HTTP unsafe format containing one "
|
||||
warnMsg += "of problematic characters: ' ,;'. temporary sanitized."
|
||||
logger.warn(warnMsg)
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user