diff --git a/lib/controller/checks.py b/lib/controller/checks.py
index 2b947f9f5..1d4d2d885 100644
--- a/lib/controller/checks.py
+++ b/lib/controller/checks.py
@@ -65,6 +65,7 @@ from lib.core.settings import LOWER_RATIO_BOUND
from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
from lib.core.threads import getCurrentThreadData
+from lib.core.wafs import wafs
from lib.request.connect import Connect as Request
from lib.request.inject import checkBooleanExpression
from lib.request.templates import getPageTemplate
@@ -1027,6 +1028,19 @@ def checkWaf():
if not falseResult:
retVal = True
+ if retVal:
+ if conf.identifyWaf:
+ infoMsg = "detecting the vendor of the waf"
+ logger.info(infoMsg)
+ for waf in wafs:
+ if waf.identify():
+ kb.waf = waf.vendor
+ infoMsg = "the vendor of the waf seems to be " + kb.waf
+ logger.info(infoMsg)
+ break
+ infoMsg = "the vendor of the waf is not detected"
+ logger.info(infoMsg)
+
conf.parameters = dict(backup)
if retVal:
diff --git a/lib/core/option.py b/lib/core/option.py
index 8244f2fc9..e50418420 100644
--- a/lib/core/option.py
+++ b/lib/core/option.py
@@ -1632,6 +1632,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.timeValidCharsRun = 0
kb.uChar = NULL
kb.unionDuplicates = False
+ kb.waf = None
kb.xpCmdshellAvailable = False
if flushAll:
diff --git a/lib/core/wafs.py b/lib/core/wafs.py
new file mode 100644
index 000000000..cedf738dd
--- /dev/null
+++ b/lib/core/wafs.py
@@ -0,0 +1,313 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+import httplib
+from lib.request.connect import Connect as Request
+from lib.core.data import conf
+from lib.core.data import kb
+from lib.core.data import logger
+from lib.core.enums import PLACE
+from lib.core.common import getHostHeader
+
+class Waf(object):
+ """
+ This class defines waf vendors and attack vectors for identification
+ """
+ attack_vectors = [
+ '/Admin_Files/',
+ '',
+ '%3Cscript%3Ealert%281%29%3C/script%3E',
+ '../../../../etc/passwd',
+ 'hello'
+ ]
+
+ def __init__(self):
+ self.vendor = None
+
+ def identify(self):
+ pass
+
+ @staticmethod
+ def matchheader(headers, field, match):
+ headers = dict(headers.items())
+ if field in headers:
+ if field == 'set-cookie':
+ values = headers[field].split('; ')
+ else:
+ values = [headers[field]]
+ for value in values:
+ if re.match(match, value, re.IGNORECASE):
+ return True
+ return False
+
+class WafProfense(Waf):
+ def __init__(self):
+ self.vendor = 'Profense'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'server', 'profense')
+
+class WafNetContinuum(Waf):
+ def __init__(self):
+ self.vendor = 'NetContinuum'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'set-cookie', '^NCI__SessionId=')
+
+class WafBarracuda(Waf):
+ def __init__(self):
+ self.vendor = 'Barracuda'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'set-cookie', '^barra_counter_session=')
+
+class WafHyperGuard(Waf):
+ def __init__(self):
+ self.vendor = 'HyperGuard'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'set-cookie', '^WODSESSION=')
+
+class WafBinarySec(Waf):
+ def __init__(self):
+ self.vendor = 'BinarySec'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'server', 'BinarySec')
+
+class WafTeros(Waf):
+ def __init__(self):
+ self.vendor = 'Teros'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'set-cookie', '^st8id=')
+
+class WafF5Trafficshield(Waf):
+ def __init__(self):
+ self.vendor = 'F5 Trafficshield'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ if Waf.matchheader(headers, 'cookie', '^ASINFO='):
+ return True
+ if Waf.matchheader(headers, 'server', 'F5-TrafficShield'):
+ return True
+ return False
+
+class WafF5ASM(Waf):
+ def __init__(self):
+ self.vendor = 'F5 ASM'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'set-cookie', '^TS[a-zA-Z0-9]{3,6}=')
+
+class WafAirlock(Waf):
+ def __init__(self):
+ self.vendor = 'Airlock'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'set-cookie', '^AL[_-]?(SESS|LB)=')
+
+class WafCitrixNetScaler(Waf):
+ def __init__(self):
+ self.vendor = 'Citrix NetScaler'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ if Waf.matchheader(headers, 'set-cookie', '^(ns_af=|citrix_ns_id|NSC_)'):
+ return True
+
+ for attack_vector in Waf.attack_vectors:
+ get = attack_vector
+ page, headers, code = Request.getPage(content=True, get=get)
+ if Waf.matchheader(headers, 'Cneonction', 'close') or Waf.matchheader(headers, 'nnCoection', 'close'):
+ return True
+ return False
+
+class WafModSecurity(Waf):
+ def __init__(self):
+ self.vendor = 'ModSecurity'
+
+ def identify(self):
+ for attack_vector in Waf.attack_vectors:
+ get = attack_vector
+ page, headers, code = Request.getPage(content=True, get=get)
+ if code == 501:
+ return True
+ return False
+
+class WafIBMWebApplicationSecurity(Waf):
+ def __init__(self):
+ self.vendor = 'IBM Web Application Security'
+
+ def identify(self):
+ get = '/Admin_Files/'
+ page, headers, code = Request.getPage(content=True, get=get)
+ if page is None:
+ return True
+ return False
+
+class WafIBMDataPower(Waf):
+ def __init__(self):
+ self.vendor = 'IBM DataPower'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ return Waf.matchheader(headers, 'X-Backside-Transport', '^(OK|FAIL)')
+
+class WafDenyALL(Waf):
+ def __init__(self):
+ self.vendor = 'DenyALL'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ if Waf.matchheader(headers, 'set-cookie', '^sessioncookie='):
+ return True
+ for attack_vector in Waf.attack_vectors:
+ get = attack_vector
+ conn, _, _ = Request.getPage(response=True, get=get)
+ if conn.code == 200:
+ if conn.msg == 'Condition Intercepted':
+ return True
+ return False
+
+class WafdotDefender(Waf):
+ def __init__(self):
+ self.vendor = 'dotDefender'
+
+ def identify(self):
+ for attack_vector in Waf.attack_vectors:
+ get = attack_vector
+ page, headers, code = Request.getPage(content=True, get=get)
+ if Waf.matchheader(headers, 'X-dotDefender-denied', '^1$'):
+ return True
+ return False
+
+class WafwebAppSecure(Waf):
+ def __init__(self):
+ self.vendor = 'webApp.secure'
+
+ def identify(self):
+ page, headers, code = Request.getPage(content=True)
+ if code == 403:
+ return False
+ get = 'nx=@@'
+ page, headers, code = Request.getPage(content=True, get=get)
+ if code == 403:
+ return True
+ return False
+
+class WafBIGIP(Waf):
+ def __init__(self):
+ self.vendor = 'BIG-IP'
+
+ def identify(self):
+ for attack_vector in Waf.attack_vectors:
+ get = attack_vector
+ page, headers, code = Request.getPage(content=True, get=get)
+ if Waf.matchheader(headers, 'X-Cnection', '^close$'):
+ return True
+ return False
+
+class WafURLScan(Waf):
+ def __init__(self):
+ self.vendor = 'URLScan'
+
+ def identify(self):
+ auxHeaders = dict()
+ auxHeaders['Translate'] = 'z'*10
+ auxHeaders['If'] = 'z'*10
+ auxHeaders['Lock-Token'] = 'z'*10
+ auxHeaders['Transfer-Encoding'] = 'z'*10
+ page, headers, code1 = Request.getPage(content=True)
+ page, headers, code2 = Request.getPage(content=True, auxHeaders=auxHeaders)
+ if code1 != code2 and code2 == 404:
+ return True
+ return False
+
+class WafWebKnight(Waf):
+ def __init__(self):
+ self.vendor = 'WebKnight'
+
+ def identify(self):
+ for attack_vector in Waf.attack_vectors:
+ get = attack_vector
+ page, headers, code = Request.getPage(content=True, get=get)
+ if code == 999:
+ return True
+ return False
+
+class WafSecureIIS(Waf):
+ def __init__(self):
+ self.vendor = 'SecureIIS'
+
+ def identify(self):
+ auxHeaders = dict()
+ auxHeaders['Transfer-Encoding'] = 'z' * 1025
+ page, headers, code = Request.getPage(content=True, auxHeaders=auxHeaders)
+ if code == 404:
+ return True
+ return False
+
+class WafImperva(Waf):
+ def __init__(self):
+ self.vendor = 'Imperva'
+
+ def identify(self):
+ for attack_vector in Waf.attack_vectors:
+ conn = httplib.HTTPConnection(getHostHeader(conf.url), conf.port)
+ conn.request('GET', '/' + attack_vector)
+ r = conn.getresponse()
+ if r.version == 10:
+ return True
+ return False
+
+class WafISAServer(Waf):
+ def __init__(self):
+ self.vendor = 'ISA Server'
+
+ def identify(self):
+ auxHeaders = dict()
+ auxHeaders['Host'] = '123456'
+ conn, _, _ = Request.getPage(response=True, auxHeaders=auxHeaders)
+ if conn.msg == 'Forbidden ( The server denied the specified Uniform Resource Locator (URL). Contact the server administrator. )':
+ return True
+ return False
+
+wafs = [
+ WafProfense(),
+ WafNetContinuum(),
+ WafBarracuda(),
+ WafHyperGuard(),
+ WafBinarySec(),
+ WafTeros(),
+ WafF5Trafficshield(),
+ WafF5ASM(),
+ WafAirlock(),
+ WafCitrixNetScaler(),
+ WafModSecurity(),
+ WafIBMWebApplicationSecurity(),
+ WafIBMDataPower(),
+ WafDenyALL(),
+ WafdotDefender(),
+ WafwebAppSecure(),
+ WafBIGIP(),
+ WafURLScan(),
+ WafWebKnight(),
+ WafSecureIIS(),
+ WafImperva(),
+ WafISAServer()
+]
diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py
index d2927b23b..e4a173284 100644
--- a/lib/parse/cmdline.py
+++ b/lib/parse/cmdline.py
@@ -616,6 +616,10 @@ def cmdLineParser():
action="store_true",
help="Heuristically check for WAF/IPS/IDS protection")
+ miscellaneous.add_option("--identify-waf", dest="identifyWaf",
+ action="store_true",
+ help="Identify the vendor of WAF")
+
miscellaneous.add_option("--cleanup", dest="cleanup",
action="store_true",
help="Clean up the DBMS by sqlmap specific "