mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-02-04 12:36:36 +00:00
Initial support for #2709 (more work to be done)
This commit is contained in:
@@ -3207,13 +3207,13 @@ def decodeIntToUnicode(value):
|
||||
|
||||
if Backend.isDbms(DBMS.MYSQL):
|
||||
# https://github.com/sqlmapproject/sqlmap/issues/1531
|
||||
retVal = getUnicode(raw, conf.charset or UNICODE_ENCODING)
|
||||
retVal = getUnicode(raw, conf.encoding or UNICODE_ENCODING)
|
||||
elif Backend.isDbms(DBMS.MSSQL):
|
||||
retVal = getUnicode(raw, "UTF-16-BE")
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE):
|
||||
retVal = unichr(value)
|
||||
else:
|
||||
retVal = getUnicode(raw, conf.charset)
|
||||
retVal = getUnicode(raw, conf.encoding)
|
||||
else:
|
||||
retVal = getUnicode(chr(value))
|
||||
except:
|
||||
|
||||
@@ -1409,8 +1409,8 @@ def _setHTTPExtraHeaders():
|
||||
raise SqlmapSyntaxException(errMsg)
|
||||
|
||||
elif not conf.requestFile and len(conf.httpHeaders or []) < 2:
|
||||
if conf.charset:
|
||||
conf.httpHeaders.append((HTTP_HEADER.ACCEPT_CHARSET, "%s;q=0.7,*;q=0.1" % conf.charset))
|
||||
if conf.encoding:
|
||||
conf.httpHeaders.append((HTTP_HEADER.ACCEPT_CHARSET, "%s;q=0.7,*;q=0.1" % conf.encoding))
|
||||
|
||||
# Invalidating any caching mechanism in between
|
||||
# Reference: http://stackoverflow.com/a/1383359
|
||||
@@ -2577,15 +2577,15 @@ def _basicOptionValidation():
|
||||
errMsg += "format <username>:<password> (e.g. \"root:pass\")"
|
||||
raise SqlmapSyntaxException(errMsg)
|
||||
|
||||
if conf.charset:
|
||||
_ = checkCharEncoding(conf.charset, False)
|
||||
if conf.encoding:
|
||||
_ = checkCharEncoding(conf.encoding, False)
|
||||
if _ is None:
|
||||
errMsg = "unknown charset '%s'. Please visit " % conf.charset
|
||||
errMsg = "unknown charset '%s'. Please visit " % conf.encoding
|
||||
errMsg += "'%s' to get the full list of " % CODECS_LIST_PAGE
|
||||
errMsg += "supported charsets"
|
||||
raise SqlmapSyntaxException(errMsg)
|
||||
else:
|
||||
conf.charset = _
|
||||
conf.encoding = _
|
||||
|
||||
if conf.loadCookies:
|
||||
if not os.path.exists(conf.loadCookies):
|
||||
|
||||
@@ -201,6 +201,7 @@ optDict = {
|
||||
"crawlExclude": "string",
|
||||
"csvDel": "string",
|
||||
"dumpFormat": "string",
|
||||
"encoding": "string",
|
||||
"eta": "boolean",
|
||||
"flushSession": "boolean",
|
||||
"forms": "boolean",
|
||||
|
||||
@@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME
|
||||
from lib.core.enums import OS
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.1.9.22"
|
||||
VERSION = "1.1.9.23"
|
||||
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)
|
||||
@@ -67,6 +67,7 @@ BOUNDED_INJECTION_MARKER = "__BOUNDED_INJECTION_MARK__"
|
||||
RANDOM_INTEGER_MARKER = "[RANDINT]"
|
||||
RANDOM_STRING_MARKER = "[RANDSTR]"
|
||||
SLEEP_TIME_MARKER = "[SLEEPTIME]"
|
||||
INFERENCE_MARKER = "[INFERENCE]"
|
||||
|
||||
PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__"
|
||||
CHAR_INFERENCE_MARK = "%c"
|
||||
@@ -175,6 +176,9 @@ INFERENCE_UNKNOWN_CHAR = '?'
|
||||
# Character used for operation "greater" in inference
|
||||
INFERENCE_GREATER_CHAR = ">"
|
||||
|
||||
# Character used for operation "greater or equal" in inference
|
||||
INFERENCE_GREATER_EQUALS_CHAR = ">="
|
||||
|
||||
# Character used for operation "equals" in inference
|
||||
INFERENCE_EQUALS_CHAR = "="
|
||||
|
||||
|
||||
@@ -631,9 +631,6 @@ def cmdLineParser(argv=None):
|
||||
general.add_option("--binary-fields", dest="binaryFields",
|
||||
help="Result fields having binary values (e.g. \"digest\")")
|
||||
|
||||
general.add_option("--charset", dest="charset",
|
||||
help="Force character encoding used for data retrieval")
|
||||
|
||||
general.add_option("--check-internet", dest="checkInternet",
|
||||
action="store_true",
|
||||
help="Check Internet connection before assessing the target")
|
||||
@@ -648,9 +645,15 @@ def cmdLineParser(argv=None):
|
||||
help="Delimiting character used in CSV output "
|
||||
"(default \"%s\")" % defaults.csvDel)
|
||||
|
||||
general.add_option("--charset", dest="charset",
|
||||
help="Blind SQL injection charset (e.g. \"0123456789abcdef\")")
|
||||
|
||||
general.add_option("--dump-format", dest="dumpFormat",
|
||||
help="Format of dumped data (CSV (default), HTML or SQLITE)")
|
||||
|
||||
general.add_option("--encoding", dest="encoding",
|
||||
help="Character encoding used for data retrieval (e.g. GBK)")
|
||||
|
||||
general.add_option("--eta", dest="eta",
|
||||
action="store_true",
|
||||
help="Display for each output the estimated time of arrival")
|
||||
|
||||
@@ -279,7 +279,7 @@ def decodePage(page, contentEncoding, contentType):
|
||||
kb.pageCompress = False
|
||||
raise SqlmapCompressionException
|
||||
|
||||
if not conf.charset:
|
||||
if not conf.encoding:
|
||||
httpCharset, metaCharset = None, None
|
||||
|
||||
# Reference: http://stackoverflow.com/questions/1020892/python-urllib2-read-to-unicode
|
||||
@@ -296,7 +296,7 @@ def decodePage(page, contentEncoding, contentType):
|
||||
else:
|
||||
kb.pageEncoding = None
|
||||
else:
|
||||
kb.pageEncoding = conf.charset
|
||||
kb.pageEncoding = conf.encoding
|
||||
|
||||
# can't do for all responses because we need to support binary files too
|
||||
if contentType and not isinstance(page, unicode) and "text/" in contentType.lower():
|
||||
|
||||
@@ -144,7 +144,7 @@ class Web:
|
||||
randInt = randomInt()
|
||||
query += "OR %d=%d " % (randInt, randInt)
|
||||
|
||||
query += getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=outFile, HEXSTRING=hexencode(uplQuery, conf.charset))
|
||||
query += getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=outFile, HEXSTRING=hexencode(uplQuery, conf.encoding))
|
||||
query = agent.prefixQuery(query)
|
||||
query = agent.suffixQuery(query)
|
||||
payload = agent.payload(newValue=query)
|
||||
|
||||
@@ -163,7 +163,7 @@ class XP_cmdshell:
|
||||
# Obfuscate the command to execute, also useful to bypass filters
|
||||
# on single-quotes
|
||||
self._randStr = randomStr(lowercase=True)
|
||||
self._cmd = "0x%s" % hexencode(cmd, conf.charset)
|
||||
self._cmd = "0x%s" % hexencode(cmd, conf.encoding)
|
||||
self._forgedCmd = "DECLARE @%s VARCHAR(8000);" % self._randStr
|
||||
self._forgedCmd += "SET @%s=%s;" % (self._randStr, self._cmd)
|
||||
|
||||
|
||||
@@ -39,7 +39,9 @@ from lib.core.settings import CHAR_INFERENCE_MARK
|
||||
from lib.core.settings import INFERENCE_BLANK_BREAK
|
||||
from lib.core.settings import INFERENCE_UNKNOWN_CHAR
|
||||
from lib.core.settings import INFERENCE_GREATER_CHAR
|
||||
from lib.core.settings import INFERENCE_GREATER_EQUALS_CHAR
|
||||
from lib.core.settings import INFERENCE_EQUALS_CHAR
|
||||
from lib.core.settings import INFERENCE_MARKER
|
||||
from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
|
||||
from lib.core.settings import MAX_BISECTION_LENGTH
|
||||
from lib.core.settings import MAX_REVALIDATION_STEPS
|
||||
@@ -67,7 +69,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
partialValue = u""
|
||||
finalValue = None
|
||||
retrievedLength = 0
|
||||
asciiTbl = getCharset(charsetType)
|
||||
|
||||
if charsetType is None and conf.charset:
|
||||
asciiTbl = sorted(set(ord(_) for _ in conf.charset))
|
||||
else:
|
||||
asciiTbl = getCharset(charsetType)
|
||||
|
||||
threadData = getCurrentThreadData()
|
||||
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
|
||||
retVal = hashDBRetrieve(expression, checkConf=True)
|
||||
@@ -109,7 +116,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
elif (kb.fileReadMode or dump) and conf.firstChar is not None and (isinstance(conf.firstChar, int) or (isinstance(conf.firstChar, basestring) and conf.firstChar.isdigit())):
|
||||
firstChar = int(conf.firstChar) - 1
|
||||
if kb.fileReadMode:
|
||||
firstChar *= 2
|
||||
firstChar <<= 1
|
||||
elif isinstance(firstChar, basestring) and firstChar.isdigit() or isinstance(firstChar, int):
|
||||
firstChar = int(firstChar) - 1
|
||||
else:
|
||||
@@ -271,7 +278,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
lastCheck = False
|
||||
unexpectedCode = False
|
||||
|
||||
while len(charTbl) != 1:
|
||||
while len(charTbl) > 1:
|
||||
position = None
|
||||
|
||||
if charsetType is None:
|
||||
@@ -444,23 +451,22 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
|
||||
if threadData.shared.index[0] - firstChar >= length:
|
||||
kb.locks.index.release()
|
||||
|
||||
return
|
||||
|
||||
threadData.shared.index[0] += 1
|
||||
curidx = threadData.shared.index[0]
|
||||
currentCharIndex = threadData.shared.index[0]
|
||||
kb.locks.index.release()
|
||||
|
||||
if kb.threadContinue:
|
||||
charStart = time.time()
|
||||
val = getChar(curidx)
|
||||
val = getChar(currentCharIndex, asciiTbl, not(charsetType is None and conf.charset))
|
||||
if val is None:
|
||||
val = INFERENCE_UNKNOWN_CHAR
|
||||
else:
|
||||
break
|
||||
|
||||
with kb.locks.value:
|
||||
threadData.shared.value[curidx - 1 - firstChar] = val
|
||||
threadData.shared.value[currentCharIndex - 1 - firstChar] = val
|
||||
currentValue = list(threadData.shared.value)
|
||||
|
||||
if kb.threadContinue:
|
||||
@@ -488,10 +494,10 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
count += 1 if currentValue[i] is not None else 0
|
||||
|
||||
if startCharIndex > 0:
|
||||
output = '..' + output[2:]
|
||||
output = ".." + output[2:]
|
||||
|
||||
if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length - 1):
|
||||
output = output[:-2] + '..'
|
||||
output = output[:-2] + ".."
|
||||
|
||||
if conf.verbose in (1, 2) and not showEta and not conf.api:
|
||||
_ = count - firstChar
|
||||
@@ -549,7 +555,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
testValue = unescaper.escape("'%s'" % commonValue) if "'" not in commonValue else unescaper.escape("%s" % commonValue, quote=False)
|
||||
|
||||
query = kb.injection.data[kb.technique].vector
|
||||
query = agent.prefixQuery(query.replace("[INFERENCE]", "(%s)=%s" % (expressionUnescaped, testValue)))
|
||||
query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)%s%s" % (expressionUnescaped, INFERENCE_EQUALS_CHAR, testValue)))
|
||||
query = agent.suffixQuery(query)
|
||||
|
||||
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
|
||||
@@ -573,7 +579,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
testValue = unescaper.escape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.escape("%s" % commonPattern, quote=False)
|
||||
|
||||
query = kb.injection.data[kb.technique].vector
|
||||
query = agent.prefixQuery(query.replace("[INFERENCE]", "(%s)=%s" % (subquery, testValue)))
|
||||
query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)=%s" % (subquery, testValue)))
|
||||
query = agent.suffixQuery(query)
|
||||
|
||||
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
|
||||
@@ -594,9 +600,9 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
|
||||
# If we had no luck with commonValue and common charset,
|
||||
# use the returned other charset
|
||||
if not val:
|
||||
val = getChar(index, otherCharset, otherCharset == asciiTbl)
|
||||
val = getChar(index, otherCharset, otherCharset==asciiTbl)
|
||||
else:
|
||||
val = getChar(index, asciiTbl)
|
||||
val = getChar(index, asciiTbl, not(charsetType is None and conf.charset))
|
||||
|
||||
if val is None:
|
||||
finalValue = partialValue
|
||||
|
||||
Reference in New Issue
Block a user