diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 3bb884199..319e87140 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -108,7 +108,6 @@ from lib.request.templates import getPageTemplate from lib.techniques.union.test import unionTest from lib.techniques.union.use import configUnion from thirdparty import six -from thirdparty.identywaf import identYwaf from thirdparty.six.moves import http_client as _http_client def checkSqlInjection(place, parameter, value): @@ -1403,49 +1402,22 @@ def checkWaf(): kb.resendPostOnRedirect = popValue() kb.redirectChoice = popValue() - # TODO: today if retVal: - pass - # identYwaf - #if conf.timeout == defaults.timeout: - #logger.warning("dropping timeout to %d seconds (i.e. '--timeout=%d')" % (IDS_WAF_CHECK_TIMEOUT, IDS_WAF_CHECK_TIMEOUT)) - #conf.timeout = IDS_WAF_CHECK_TIMEOUT + if not kb.identifiedWafs: + warnMsg = "heuristics detected that the target " + warnMsg += "is protected by some kind of WAF/IPS" + logger.critical(warnMsg) - # identYwaf + message = "are you sure that you want to " + message += "continue with further target testing? [y/N] " + choice = readInput(message, default='N', boolean=True) - #def _(*args, **kwargs): - #page, headers, code = None, None, None - #try: - #pushValue(kb.redirectChoice) - #pushValue(kb.resendPostOnRedirect) + if not conf.tamper: + warnMsg = "please consider usage of tamper scripts (option '--tamper')" + singleTimeWarnMessage(warnMsg) - #kb.redirectChoice = REDIRECTION.YES - #kb.resendPostOnRedirect = True - - #if kwargs.get("get"): - #kwargs["get"] = urlencode(kwargs["get"]) - #kwargs["raise404"] = False - #kwargs["silent"] = True - #kwargs["finalCode"] = True - - #page, headers, code = Request.getPage(*args, **kwargs) - #except Exception: - #pass - #finally: - #kb.resendPostOnRedirect = popValue() - #kb.redirectChoice = popValue() - - - #message = "are you sure that you want to " - #message += "continue with further target testing? [y/N] " - #choice = readInput(message, default='N', boolean=True) - - #if not conf.tamper: - #warnMsg = "please consider usage of tamper scripts (option '--tamper')" - #singleTimeWarnMessage(warnMsg) - - #if not choice: - #raise SqlmapUserQuitException + if not choice: + raise SqlmapUserQuitException hashDBWrite(HASHDB_KEYS.CHECK_WAF_RESULT, retVal, True) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index e80f3d9a0..f96db7a95 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -290,6 +290,7 @@ DEPRECATED_OPTIONS = { "--purge-output": "use '--purge' instead", "--check-payload": None, "--check-waf": None, + "--identify-waf": None, "--pickled-options": "use '--api -c ...' instead", } diff --git a/lib/core/option.py b/lib/core/option.py index b8e893f53..4b0087a6a 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1890,6 +1890,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.ignoreCasted = None kb.ignoreNotFound = False kb.ignoreTimeout = False + kb.identifiedWafs = set() kb.injection = InjectionDict() kb.injections = [] kb.laggingChecked = False @@ -1970,7 +1971,6 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.tableExistsChoice = None kb.uChar = NULL kb.unionDuplicates = False - kb.wafSpecificResponse = None kb.wizardMode = False kb.xpCmdshellAvailable = False diff --git a/lib/core/settings.py b/lib/core/settings.py index a0c908d54..00ba78f53 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.5.131" +VERSION = "1.3.5.132" 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) diff --git a/lib/request/basic.py b/lib/request/basic.py index 2b50b56ea..27d151736 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -51,8 +51,10 @@ from lib.parse.html import htmlParser from lib.utils.htmlentities import htmlEntities from thirdparty import six from thirdparty.chardet import detect +from thirdparty.identywaf import identYwaf from thirdparty.odict import OrderedDict from thirdparty.six import unichr as _unichr +from thirdparty.six.moves import http_client as _http_client def forgeHeaders(items=None, base=None): """ @@ -365,7 +367,7 @@ def decodePage(page, contentEncoding, contentType): return page -def processResponse(page, responseHeaders, status=None): +def processResponse(page, responseHeaders, code=None, status=None): kb.processResponseCounter += 1 page = page or "" @@ -383,6 +385,16 @@ def processResponse(page, responseHeaders, status=None): if msg: logger.warning("parsed DBMS error message: '%s'" % msg.rstrip('.')) + rawResponse = "%s %s %s\n%s\n%s" % (_http_client.HTTPConnection._http_vsn_str, code or "", status or "", "".join(responseHeaders.headers), page) + + identYwaf.non_blind.clear() + if identYwaf.non_blind_check(rawResponse, silent=True): + for waf in identYwaf.non_blind: + if waf not in kb.identifiedWafs: + kb.identifiedWafs.add(waf) + errMsg = "WAF/IPS identified as '%s'" % identYwaf.format_name(waf) + singleTimeLogMessage(errMsg, logging.CRITICAL) + if kb.originalPage is None: for regex in (EVENTVALIDATION_REGEX, VIEWSTATE_REGEX): match = re.search(regex, page) diff --git a/lib/request/connect.py b/lib/request/connect.py index 0c4343f36..ce2ec3af4 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -795,7 +795,7 @@ class Connect(object): socket.setdefaulttimeout(conf.timeout) - processResponse(page, responseHeaders, status) + processResponse(page, responseHeaders, code, status) if not skipLogTraffic: if conn and getattr(conn, "redurl", None): diff --git a/thirdparty/identywaf/identYwaf.py b/thirdparty/identywaf/identYwaf.py index 3a9148bc7..5a42e5f5f 100755 --- a/thirdparty/identywaf/identYwaf.py +++ b/thirdparty/identywaf/identYwaf.py @@ -66,7 +66,7 @@ else: sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout) NAME = "identYwaf" -VERSION = "1.0.108" +VERSION = "1.0.110" BANNER = """ ` __ __ ` ____ ___ ___ ____ ______ `| T T` __ __ ____ _____ @@ -396,7 +396,7 @@ def init(): def format_name(waf): return "%s%s" % (DATA_JSON["wafs"][waf]["name"], (" (%s)" % DATA_JSON["wafs"][waf]["company"]) if DATA_JSON["wafs"][waf]["name"] != DATA_JSON["wafs"][waf]["company"] else "") -def non_blind_check(raw): +def non_blind_check(raw, silent=False): retval = False match = re.search(WAF_RECOGNITION_REGEX, raw or "") if match: @@ -405,7 +405,8 @@ def non_blind_check(raw): if match.group(_): waf = re.sub(r"\Awaf_", "", _) non_blind.add(waf) - single_print(colorize("[+] non-blind match: '%s'%s" % (format_name(waf), 20 * ' '))) + if not silent: + single_print(colorize("[+] non-blind match: '%s'%s" % (format_name(waf), 20 * ' '))) return retval def run():