diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 8f2beee05..ce2767988 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -26,12 +26,15 @@ import re import socket import time +from difflib import SequenceMatcher + from lib.core.agent import agent from lib.core.common import getUnicode from lib.core.common import preparePageForLineComparison from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import readInput +from lib.core.common import showStaticWords from lib.core.common import DynamicContentItem from lib.core.convert import md5hash from lib.core.data import conf @@ -41,6 +44,7 @@ from lib.core.data import paths from lib.core.exception import sqlmapConnectionException from lib.core.exception import sqlmapNoneDataException from lib.core.exception import sqlmapUserQuitException +from lib.core.exception import sqlmapSilentQuitException from lib.core.session import setString from lib.core.session import setRegexp from lib.request.connect import Connect as Request @@ -251,13 +255,28 @@ def checkStability(): warnMsg += "manual paragraph 'Page comparison' and provide a " warnMsg += "string or regular expression to match on" logger.warn(warnMsg) - - message = "do you still want to continue (possible BAD results)? [Y/n] " - test = readInput(message, default="Y") - if test and test[0] not in ("y", "Y"): - raise sqlmapUserQuitException - checkDynamicContent(firstPage, secondPage) + message = "how do you want to proceed? [C(ontinue)/s(tring)/r(egex)/q(uit)] " + test = readInput(message, default="C") + if test and test[0] in ("q", "Q"): + raise sqlmapUserQuitException + elif test and test[0] in ("s", "S"): + showStaticWords(firstPage, secondPage) + message = "please enter value for parameter 'string': " + test = readInput(message) + if test: + conf.string = test + else: + raise sqlmapSilentQuitException + elif test and test[0] in ("r", "R"): + message = "please enter value for parameter 'regex': " + test = readInput(message) + if test: + conf.regex = test + else: + raise sqlmapSilentQuitException + else: + checkDynamicContent(firstPage, secondPage) return condition diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 5ee884d92..6e7ae9571 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -40,6 +40,7 @@ from lib.core.data import kb from lib.core.data import logger from lib.core.exception import exceptionsTuple from lib.core.exception import sqlmapNotVulnerableException +from lib.core.exception import sqlmapSilentQuitException from lib.core.exception import sqlmapUserQuitException from lib.core.session import setInjection from lib.core.target import initTargetEnv @@ -286,6 +287,9 @@ def start(): checkForParenthesis() action() + except sqlmapSilentQuitException: + raise + except sqlmapUserQuitException: raise diff --git a/lib/core/common.py b/lib/core/common.py index e64d17dd7..b9564207f 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -39,6 +39,7 @@ import subprocess from ConfigParser import DEFAULTSECT from ConfigParser import RawConfigParser from StringIO import StringIO +from difflib import SequenceMatcher from subprocess import PIPE from subprocess import Popen as execute from tempfile import NamedTemporaryFile @@ -1124,6 +1125,33 @@ def preparePageForLineComparison(page): return page.replace("><", ">\n<").replace("
", "\n").splitlines() return retVal +def getFilteredPageContent(page): + retVal = page + if isinstance(page, basestring): + retVal = re.sub(r"(?s)||<[^>]+>|\t|\n|\r", "", page) + return retVal + +def getPageTextWordsSet(page): + retVal = None + if isinstance(page, basestring): + page = getFilteredPageContent(page) + retVal = set(re.findall(r"\w+", page)) + return retVal + +def showStaticWords(firstPage, secondPage): + infoMsg = "finding static words in longest matching part of dynamic page content" + logger.info(infoMsg) + firstPage = getFilteredPageContent(firstPage) + secondPage = getFilteredPageContent(secondPage) + match = SequenceMatcher(None, firstPage, secondPage).find_longest_match(0, len(firstPage), 0, len(secondPage)) + commonText = firstPage[match[0]:match[0]+match[2]] + commonWords = getPageTextWordsSet(commonText) + infoMsg = "static words: " + for word in commonWords: + if len(word) > 2: + infoMsg += "'%s', " % word + logger.info(infoMsg) + def decloakToNamedTemporaryFile(filepath, name=None): retVal = NamedTemporaryFile() diff --git a/lib/core/exception.py b/lib/core/exception.py index 76c864e2e..ee269bfde 100644 --- a/lib/core/exception.py +++ b/lib/core/exception.py @@ -55,6 +55,9 @@ class sqlmapNoneDataException(Exception): class sqlmapNotVulnerableException(Exception): pass +class sqlmapSilentQuitException(Exception): + pass + class sqlmapUserQuitException(Exception): pass @@ -96,6 +99,7 @@ exceptionsTuple = ( sqlmapMissingDependence, sqlmapMissingMandatoryOptionException, sqlmapNoneDataException, + sqlmapSilentQuitException, sqlmapUserQuitException, sqlmapRegExprException, sqlmapSyntaxException, diff --git a/sqlmap.py b/sqlmap.py index 5342bd245..c6384f0ab 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -51,6 +51,7 @@ from lib.core.data import conf from lib.core.data import logger from lib.core.data import paths from lib.core.exception import exceptionsTuple +from lib.core.exception import sqlmapSilentQuitException from lib.core.exception import sqlmapUserQuitException from lib.core.exception import unhandledException from lib.core.option import init @@ -100,6 +101,9 @@ def main(): logger.error(errMsg) closeDumper(False, errMsg) + except sqlmapSilentQuitException: + closeDumper(False) + except exceptionsTuple, e: e = getUnicode(e) logger.critical(e)