diff --git a/lib/controller/checks.py b/lib/controller/checks.py
index 9cebc61fd..2c38ece1b 100644
--- a/lib/controller/checks.py
+++ b/lib/controller/checks.py
@@ -36,6 +36,7 @@ from lib.core.common import readInput
from lib.core.common import showStaticWords
from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage
+from lib.core.common import urlencode
from lib.core.common import wasLastResponseDBMSError
from lib.core.common import wasLastResponseHTTPError
from lib.core.data import conf
@@ -43,6 +44,7 @@ from lib.core.data import kb
from lib.core.data import logger
from lib.core.datatype import AttribDict
from lib.core.datatype import InjectionDict
+from lib.core.decorators import cachedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS
from lib.core.enums import HEURISTIC_TEST
@@ -1045,15 +1047,26 @@ def identifyWaf():
infoMsg += "backend WAF/IPS/IDS protection"
logger.info(infoMsg)
+ @cachedmethod
+ def _(*args, **kwargs):
+ try:
+ if kwargs.get("get"):
+ kwargs["get"] = urlencode(kwargs["get"])
+ kwargs["raise404"] = False
+ return Request.getPage(*args, **kwargs)
+ except Exception, ex:
+ return None, None, None
+
retVal = False
- page, headers, code = Request.getPage()
for function, product, request in kb.wafFunctions:
found = False
+
if not request:
- found = function(page or "", headers or {}, code)
+ found = function(_)
else:
pass
+
if found:
retVal = product
break
@@ -1063,7 +1076,7 @@ def identifyWaf():
warnMsg += "consider usage of tamper scripts (option '--tamper')"
logger.critical(warnMsg)
else:
- warnMsg = "no WAF/IDS/IPS were identified"
+ warnMsg = "WAF/IDS/IPS product not identified"
logger.warn(warnMsg)
return retVal
diff --git a/lib/core/enums.py b/lib/core/enums.py
index d24fcee6c..1247735d8 100644
--- a/lib/core/enums.py
+++ b/lib/core/enums.py
@@ -150,13 +150,9 @@ class HTTPHEADER:
PROXY_CONNECTION = "Proxy-Connection"
RANGE = "Range"
REFERER = "Referer"
+ SERVER = "Server"
USER_AGENT = "User-Agent"
-class WAF_REQUEST:
- GET = 1
- POST = 2
- HEADERS = 3
-
class EXPECTED:
BOOL = "bool"
INT = "int"
diff --git a/lib/core/option.py b/lib/core/option.py
index 5db03a850..4cd87bf3b 100644
--- a/lib/core/option.py
+++ b/lib/core/option.py
@@ -905,6 +905,9 @@ def _setWafFunctions():
dirname, filename = os.path.split(found)
dirname = os.path.abspath(dirname)
+ if filename == "__init__.py":
+ continue
+
debugMsg = "loading WAF script '%s'" % filename[:-3]
logger.debug(debugMsg)
diff --git a/lib/core/settings.py b/lib/core/settings.py
index 04bc42b5b..6b01a4b0c 100644
--- a/lib/core/settings.py
+++ b/lib/core/settings.py
@@ -380,7 +380,15 @@ BRUTE_TABLE_EXISTS_TEMPLATE = "EXISTS(SELECT %d FROM %s)"
BRUTE_COLUMN_EXISTS_TEMPLATE = "EXISTS(SELECT %s FROM %s)"
# Payload used for checking of existence of IDS/WAF (dummier the better)
-IDS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,2,3,table_name FROM information_schema.tables"
+IDS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,2,3,table_name FROM information_schema.tables WHERE 2>1"
+
+# Vectors used for provoking specific WAF/IDS/IPS behavior(s)
+WAF_ATTACK_VECTORS = (
+ "search=",
+ "file=../../../../etc/passwd",
+ "q=foobar",
+ "id=1 %s" % IDS_WAF_CHECK_PAYLOAD
+ )
# Used for status representation in dictionary attack phase
ROTATING_CHARS = ('\\', '|', '|', '/', '-')
diff --git a/waf/__init__.py b/waf/__init__.py
new file mode 100644
index 000000000..9e1072a9c
--- /dev/null
+++ b/waf/__init__.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+pass
diff --git a/waf/airlock.py b/waf/airlock.py
new file mode 100644
index 000000000..5e1fe68b4
--- /dev/null
+++ b/waf/airlock.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "Airlock (Phion/Ergon)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"\AAL[_-]?(SESS|LB)=", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
diff --git a/waf/barracuda.py b/waf/barracuda.py
new file mode 100644
index 000000000..9a44346e9
--- /dev/null
+++ b/waf/barracuda.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "Barracuda Web Application Firewall (Barracuda Networks)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"\Abarra_counter_session=", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
diff --git a/waf/bigip.py b/waf/bigip.py
new file mode 100644
index 000000000..322a234c9
--- /dev/null
+++ b/waf/bigip.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+from lib.core.settings import WAF_ATTACK_VECTORS
+
+__product__ = "BIG-IP Application Security Manager (F5 Networks)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ retval = re.search(r"\ATS[a-zA-Z0-9]{3,6}=", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
+
+ if not retval:
+ for vector in WAF_ATTACK_VECTORS:
+ page, headers, code = get_page(get=vector)
+ retval = headers.get("X-Cnection", "").lower() == "close"
+ if retval:
+ break
+
+ return retval
diff --git a/waf/binarysec.py b/waf/binarysec.py
new file mode 100644
index 000000000..a870d5192
--- /dev/null
+++ b/waf/binarysec.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "BinarySEC Web Application Firewall (BinarySEC)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"BinarySec", headers.get(HTTPHEADER.SERVER, ""), re.I) is not None
diff --git a/waf/datapower.py b/waf/datapower.py
new file mode 100644
index 000000000..aea59b01c
--- /dev/null
+++ b/waf/datapower.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+__product__ = "IBM WebSphere DataPower (IBM)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"\A(OK|FAIL)", headers.get("X-Backside-Transport", ""), re.I) is not None
diff --git a/waf/denyall.py b/waf/denyall.py
new file mode 100644
index 000000000..ebc7ebec0
--- /dev/null
+++ b/waf/denyall.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+from lib.core.settings import WAF_ATTACK_VECTORS
+
+__product__ = "Deny All Web Application Firewall (DenyAll)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ retval = re.search(r"\Asessioncookie=", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
+
+ if not retval:
+ for vector in WAF_ATTACK_VECTORS:
+ page, headers, code = get_page(get=vector)
+ retval = code == 200 and re.search(r"\ACondition Intercepted", page, re.I) is not None
+ if retval:
+ break
+
+ return retval
diff --git a/waf/dotdefender.py b/waf/dotdefender.py
new file mode 100644
index 000000000..3f9a192c0
--- /dev/null
+++ b/waf/dotdefender.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+from lib.core.settings import WAF_ATTACK_VECTORS
+
+__product__ = "dotDefender (Applicure Technologies)"
+
+def detect(get_page):
+ retval = False
+
+ for vector in WAF_ATTACK_VECTORS:
+ page, headers, code = get_page(get=vector)
+ retVal = headers.get("X-dotDefender-denied", "") == 1
+ if retVal:
+ break
+
+ return retval
diff --git a/waf/f5asm.py b/waf/f5asm.py
deleted file mode 100644
index 8aeaf19f7..000000000
--- a/waf/f5asm.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
-See the file 'doc/COPYING' for copying permission
-"""
-
-import re
-
-from lib.core.enums import HTTPHEADER
-
-__product__ = "F5 Networks BIG-IP Application Security Manager (ASM)"
-__request__ = ()
-
-def detect(page, headers, code):
- return re.search(r"^TS[a-zA-Z0-9]{3,6}=", headers.get(HTTPHEADER.SET_COOKIE, "")) is not None
diff --git a/waf/hyperguard.py b/waf/hyperguard.py
new file mode 100644
index 000000000..5a72be2d3
--- /dev/null
+++ b/waf/hyperguard.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "Hyperguard Web Application Firewall (art of defence Inc.)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"\AODSESSION=", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
diff --git a/waf/modsecurity.py b/waf/modsecurity.py
new file mode 100644
index 000000000..5fcf3cec4
--- /dev/null
+++ b/waf/modsecurity.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+from lib.core.settings import WAF_ATTACK_VECTORS
+
+__product__ = "ModSecurity: Open Source Web Application Firewall (Trustwave)"
+
+def detect(get_page):
+ retval = False
+
+ for vector in WAF_ATTACK_VECTORS:
+ page, headers, code = get_page(get=vector)
+ if code == 501:
+ retVal = True
+ break
+
+ return retval
diff --git a/waf/netcontinuum.py b/waf/netcontinuum.py
new file mode 100644
index 000000000..60624b4a4
--- /dev/null
+++ b/waf/netcontinuum.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "NetContinuum Web Application Firewall (NetContinuum/Barracuda Networks)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"\ANCI__SessionId=", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
diff --git a/waf/netscaler.py b/waf/netscaler.py
new file mode 100644
index 000000000..21b162459
--- /dev/null
+++ b/waf/netscaler.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+from lib.core.settings import WAF_ATTACK_VECTORS
+
+__product__ = "NetScaler (Citrix Systems)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ retval = re.search(r"\A(ns_af=|citrix_ns_id|NSC_)", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
+
+ if not retval:
+ for vector in WAF_ATTACK_VECTORS:
+ page, headers, code = get_page(get=vector)
+ retval = re.search(r"\Aclose", headers.get("Cneonction", "") or headers.get("nnCoection", ""), re.I) is not None
+ if retval:
+ break
+
+ return retval
diff --git a/waf/profense.py b/waf/profense.py
new file mode 100644
index 000000000..816b8f23e
--- /dev/null
+++ b/waf/profense.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "Profense Web Application Firewall (Armorlogic)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"Profense", headers.get(HTTPHEADER.SERVER, ""), re.I) is not None
diff --git a/waf/proventia.py b/waf/proventia.py
new file mode 100644
index 000000000..615c96a7b
--- /dev/null
+++ b/waf/proventia.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.data import kb
+from lib.core.enums import HTTPHEADER
+from lib.core.settings import WAF_ATTACK_VECTORS
+
+__product__ = "Proventia Web Application Security (IBM)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ if page is None:
+ return False
+ page, headers, code = get_page(url="/Admin_Files/")
+ return page is None
diff --git a/waf/teros.py b/waf/teros.py
new file mode 100644
index 000000000..aaf1a2df8
--- /dev/null
+++ b/waf/teros.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "ISV Teros Web Application Firewall (Teros/Citrix Systems)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return re.search(r"\Ast8id=", headers.get(HTTPHEADER.SET_COOKIE, ""), re.I) is not None
diff --git a/waf/trafficshield.py b/waf/trafficshield.py
new file mode 100644
index 000000000..b167f11e9
--- /dev/null
+++ b/waf/trafficshield.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.enums import HTTPHEADER
+
+__product__ = "TrafficShield (F5 Networks)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ return (re.search(r"\AASINFO=", headers.get(HTTPHEADER.COOKIE, ""), re.I) or re.search(r"F5-TrafficShield", headers.get(HTTPHEADER.SERVER, ""), re.I)) is not None
diff --git a/waf/webappsecure.py b/waf/webappsecure.py
new file mode 100644
index 000000000..f51443808
--- /dev/null
+++ b/waf/webappsecure.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+"""
+Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
+See the file 'doc/COPYING' for copying permission
+"""
+
+import re
+
+from lib.core.data import kb
+from lib.core.enums import HTTPHEADER
+from lib.core.settings import WAF_ATTACK_VECTORS
+
+__product__ = "webApp.secure (webScurity)"
+
+def detect(get_page):
+ page, headers, code = get_page()
+ if code == 403:
+ return False
+ page, headers, code = get_page(get="nx=@@")
+ return code == 403