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)