mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-26 17:39:03 +00:00
Update for an Issue #2384
This commit is contained in:
@@ -20,6 +20,7 @@ from lib.core.common import extractRegexResult
|
||||
from lib.core.common import extractTextTagContent
|
||||
from lib.core.common import findDynamicContent
|
||||
from lib.core.common import Format
|
||||
from lib.core.common import getFilteredPageContent
|
||||
from lib.core.common import getLastRequestHTTPError
|
||||
from lib.core.common import getPublicTypeMembers
|
||||
from lib.core.common import getSafeExString
|
||||
@@ -63,6 +64,7 @@ from lib.core.exception import SqlmapConnectionException
|
||||
from lib.core.exception import SqlmapNoneDataException
|
||||
from lib.core.exception import SqlmapSilentQuitException
|
||||
from lib.core.exception import SqlmapUserQuitException
|
||||
from lib.core.settings import CANDIDATE_SENTENCE_MIN_LENGTH
|
||||
from lib.core.settings import DEFAULT_GET_POST_DELIMITER
|
||||
from lib.core.settings import DUMMY_NON_SQLI_CHECK_APPENDIX
|
||||
from lib.core.settings import FI_ERROR_REGEX
|
||||
@@ -478,6 +480,26 @@ def checkSqlInjection(place, parameter, value):
|
||||
|
||||
injectable = True
|
||||
|
||||
elif threadData.lastComparisonRatio > UPPER_RATIO_BOUND and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
|
||||
originalSet = set(getFilteredPageContent(kb.pageTemplate, True, "\n").split("\n"))
|
||||
trueSet = set(getFilteredPageContent(truePage, True, "\n").split("\n"))
|
||||
falseSet = set(getFilteredPageContent(falsePage, True, "\n").split("\n"))
|
||||
|
||||
if originalSet == trueSet != falseSet:
|
||||
candidates = trueSet - falseSet
|
||||
|
||||
if candidates:
|
||||
candidates = sorted(candidates, key=lambda _: len(_))
|
||||
for candidate in candidates:
|
||||
if re.match(r"\A[\w.,! ]+\Z", candidate) and ' ' in candidate and len(candidate) > CANDIDATE_SENTENCE_MIN_LENGTH:
|
||||
conf.string = candidate
|
||||
injectable = True
|
||||
|
||||
infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'"))
|
||||
logger.info(infoMsg)
|
||||
|
||||
break
|
||||
|
||||
if injectable:
|
||||
if kb.pageStable and not any((conf.string, conf.notString, conf.regexp, conf.code, kb.nullConnection)):
|
||||
if all((falseCode, trueCode)) and falseCode != trueCode:
|
||||
|
||||
@@ -1755,7 +1755,7 @@ def safeStringFormat(format_, params):
|
||||
break
|
||||
return retVal
|
||||
|
||||
def getFilteredPageContent(page, onlyText=True):
|
||||
def getFilteredPageContent(page, onlyText=True, split=" "):
|
||||
"""
|
||||
Returns filtered page content without script, style and/or comments
|
||||
or all HTML tags
|
||||
@@ -1768,10 +1768,10 @@ def getFilteredPageContent(page, onlyText=True):
|
||||
|
||||
# only if the page's charset has been successfully identified
|
||||
if isinstance(page, unicode):
|
||||
retVal = re.sub(r"(?si)<script.+?</script>|<!--.+?-->|<style.+?</style>%s" % (r"|<[^>]+>|\t|\n|\r" if onlyText else ""), " ", page)
|
||||
while retVal.find(" ") != -1:
|
||||
retVal = retVal.replace(" ", " ")
|
||||
retVal = htmlunescape(retVal.strip())
|
||||
retVal = re.sub(r"(?si)<script.+?</script>|<!--.+?-->|<style.+?</style>%s" % (r"|<[^>]+>|\t|\n|\r" if onlyText else ""), split, page)
|
||||
while retVal.find(2 * split) != -1:
|
||||
retVal = retVal.replace(2 * split, split)
|
||||
retVal = htmlunescape(retVal.strip().strip(split))
|
||||
|
||||
return retVal
|
||||
|
||||
|
||||
@@ -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.2.3"
|
||||
VERSION = "1.1.2.4"
|
||||
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)
|
||||
@@ -359,6 +359,9 @@ MIN_RATIO = 0.0
|
||||
# Maximum value for comparison ratio
|
||||
MAX_RATIO = 1.0
|
||||
|
||||
# Minimum length of sentence for automatic choosing of --string (in case of high matching ratio)
|
||||
CANDIDATE_SENTENCE_MIN_LENGTH = 10
|
||||
|
||||
# Character used for marking injectable position inside provided data
|
||||
CUSTOM_INJECTION_MARK_CHAR = '*'
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class _ThreadData(threading.local):
|
||||
self.lastComparisonPage = None
|
||||
self.lastComparisonHeaders = None
|
||||
self.lastComparisonCode = None
|
||||
self.lastComparisonRatio = None
|
||||
self.lastErrorPage = None
|
||||
self.lastHTTPError = None
|
||||
self.lastRedirectMsg = None
|
||||
|
||||
@@ -144,6 +144,9 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
|
||||
kb.matchRatio = ratio
|
||||
logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio)
|
||||
|
||||
if kb.testMode:
|
||||
threadData.lastComparisonRatio = ratio
|
||||
|
||||
# If it has been requested to return the ratio and not a comparison
|
||||
# response
|
||||
if getRatioValue:
|
||||
|
||||
Reference in New Issue
Block a user