├── .travis.yml ├── LICENSE ├── README.md ├── data.json ├── identYwaf.py └── screenshots ├── 360.png ├── aesecure.png ├── airlock.png ├── alertlogic.png ├── aliyundun.png ├── anquanbao.png ├── approach.png ├── armor.png ├── asm.png ├── astra.png ├── aws.png ├── barracuda.png ├── bekchy.png ├── bitninja.png ├── bluedon.png ├── bulletproof.png ├── cdnns.png ├── cerber.png ├── chuangyu.png ├── cloudbric.png ├── cloudflare.png ├── cloudfront.png ├── comodo.png ├── crawlprotect.png ├── distil.png ├── dotdefender.png ├── duedge.png ├── expressionengine.png ├── fortiweb.png ├── godaddy.png ├── greywizard.png ├── gtmc.png ├── imunify360.png ├── incapsula.png ├── janusec.png ├── jiasule.png ├── kona.png ├── kuipernet.png ├── malcare.png ├── modsecurity.png ├── naxsi.png ├── netscaler.png ├── newdefend.png ├── nexusguard.png ├── ninjafirewall.png ├── onmessageshield.png ├── openrasp.png ├── paloalto.png ├── profense.png ├── radware.png ├── reblaze.png ├── requestvalidationmode.png ├── rsfirewall.png ├── safe3.png ├── safedog.png ├── safeline.png ├── secupress.png ├── secureentry.png ├── secureiis.png ├── securesphere.png ├── shieldsecurity.png ├── siteground.png ├── siteguard.png ├── sitelock.png ├── sonicwall.png ├── squarespace.png ├── stackpath.png ├── sucuri.png ├── tencent.png ├── urlmaster.png ├── urlscan.png ├── vercel.png ├── virusdie.png ├── vsf.png ├── wallarm.png ├── watchguard.png ├── webarx.png ├── webknight.png ├── webland.png ├── wordfence.png ├── wts.png ├── yundun.png ├── yunsuo.png └── zenedge.png /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | dist: trusty 3 | sudo: false 4 | git: 5 | depth: 1 6 | python: 7 | - "2.6" 8 | - "2.7" 9 | - "3.3" 10 | - "3.6" 11 | script: 12 | - python -c "import identYwaf" 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2022 Miroslav Stampar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://i.imgur.com/75HpbHJ.png) 2 | 3 | [![Build Status](https://api.travis-ci.org/stamparm/identYwaf.svg?branch=master)](https://travis-ci.org/stamparm/identYwaf) [![Python 2.x|3.x](https://img.shields.io/badge/python-2.x|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/stamparm/identYwaf/blob/master/LICENSE) [![WAFs 80](https://img.shields.io/badge/WAFs-80-red.svg)](https://github.com/stamparm/identYwaf/blob/master/data.json) 4 | 5 | **identYwaf** is an identification tool that can recognize web protection type (i.e. WAF) based on blind inference. Blind inference is being done by inspecting responses provoked by a set of predefined offensive (non-destructive) payloads, where those are used only to trigger the web protection system in between (e.g. `http://?aeD0oowi=1 AND 2>1`). Currently it supports more than 80 different protection products (e.g. `aeSecure`, `Airlock`, `CleanTalk`, `CrawlProtect`, `Imunify360`, `MalCare`, `ModSecurity`, `Palo Alto`, `SiteGuard`, `UrlScan`, `Wallarm`, `WatchGuard`, `Wordfence`, etc.), while the knowledge-base is constantly growing. 6 | 7 | For more information you can check [slides](https://www.slideshare.net/stamparm/blind-waf-identification) for a talk "**Blind WAF identification**" held at *Sh3llCON 2019* (Santander / Spain). 8 | 9 | Note: as part of this project, [screenshots](https://github.com/stamparm/identYwaf/tree/master/screenshots) of characteristic responses for different web protection systems are being gathered (manually) for the future reference. 10 | 11 | ## Screenshots 12 | 13 | ![](https://imgur.com/AZVi9vB.png) 14 | 15 | ![](https://i.imgur.com/tSOAgnn.png) 16 | 17 | ![](https://imgur.com/FJchQI0.png) 18 | 19 | ![](https://imgur.com/RqQdVJJ.png) 20 | 21 | ![](https://imgur.com/weHTSv9.png) 22 | 23 | ![](https://imgur.com/UKW2cRs.png) 24 | 25 | ![](https://imgur.com/20cd08y.png) 26 | 27 | ## Installation 28 | 29 | You can download the latest zipball by clicking [here](https://github.com/stamparm/identYwaf/archive/master.zip). 30 | 31 | Preferably, you can download identYwaf by cloning the Git repository: 32 | 33 | `git clone --depth 1 https://github.com/stamparm/identYwaf.git` 34 | 35 | **identYwaf** works out of the box with any Python version from **2.6.x** to **3.x** on any platform. 36 | 37 | ## Usage 38 | 39 | ``` 40 | $ python identYwaf.py 41 | __ __ 42 | ____ ___ ___ ____ ______ | T T __ __ ____ _____ 43 | l j| \ / _]| \ | T| | || T__T T / T| __| 44 | | T | \ / [_ | _ Yl_j l_j| ~ || | | |Y o || l_ 45 | | | | D YY _]| | | | | |___ || | | || || _| 46 | j l | || [_ | | | | | | ! \ / | | || ] 47 | |____jl_____jl_____jl__j__j l__j l____/ \_/\_/ l__j__jl__j (1.0.XX) 48 | 49 | Usage: python identYwaf.py [options] 50 | 51 | Options: 52 | --version Show program's version number and exit 53 | -h, --help Show this help message and exit 54 | --delay=DELAY Delay (sec) between tests (default: 0) 55 | --timeout=TIMEOUT Response timeout (sec) (default: 10) 56 | --proxy=PROXY HTTP proxy address (e.g. "http://127.0.0.1:8080") 57 | --proxy-file=PRO.. Load (rotating) HTTP(s) proxy list from a file 58 | --random-agent Use random HTTP User-Agent header value 59 | --code=CODE Expected HTTP code in rejected responses 60 | --string=STRING Expected string in rejected responses 61 | --post Use POST body for sending payloads 62 | ``` 63 | -------------------------------------------------------------------------------- /data.json: -------------------------------------------------------------------------------- 1 | { 2 | "__copyright__": "Copyright (c) 2019-2021 Miroslav Stampar (@stamparm), MIT. See the file 'LICENSE' for copying permission", 3 | "__notice__": "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software", 4 | 5 | "payloads": [ 6 | "HTML::", 7 | "SQLi::1 AND 1", 8 | "SQLi::1/**/AND/**/1", 9 | "SQLi::1/*0AND*/1", 10 | "SQLi::1 AND 1=1", 11 | "SQLi::1 AND 1 LIKE 1", 12 | "SQLi::1 AND 1 BETWEEN 0 AND 1", 13 | "SQLi::1 AND 2>(SELECT 1)-- -", 14 | "SQLi::' OR SLEEP(5) OR '", 15 | "SQLi::admin'-- -", 16 | "SQLi::information_schema", 17 | "SQLi::;DROP TABLE mysql.users", 18 | "SQLi::';DROP DATABASE mysql#", 19 | "SQLi::1/**/UNION/**/SELECT/**/1/**/FROM/**/information_schema.*", 20 | "SQLi::SELECT id FROM users WHERE id>2", 21 | "SQLi::1 UNION SELECT information_schema.*", 22 | "SQLi::1;EXEC xp_cmdshell('type autoexec.bat');", 23 | "SQLi::1;INSERT INTO USERS values('admin', 'foobar')", 24 | "XSS::", 25 | "XSS::", 26 | "XSS::", 28 | "XSS::\\\";alert('XSS');//", 29 | "XSS::1' onerror=alert(String.fromCharCode(88,83,83))>", 30 | "XSS::var n=0;while(true){n++;}]]>", 31 | "XSS::", 32 | "XSS::javascript:alert(/XSS/)", 33 | "XSS::", 34 | "XPATHi::' and count(/*)=1 and '1'='1", 35 | "XPATHi::count(/child::node())", 36 | "XPATHi::' and count(/comment())=1 and '1'='1", 37 | "XPATHi::' or '1'='1", 38 | "XXE::]>&xxe;", 39 | "LDAPi::admin*)((|userpassword=*)", 40 | "LDAPi::user=*)(uid=*))(|(uid=*", 41 | "LDAPi::*(|(objectclass=*))", 42 | "NOSQLi::true, $where: '1 == 1'", 43 | "NOSQLi::{ $ne: 1 }", 44 | "NOSQLi::' } ], $comment:'success'", 45 | "PHPi::", 46 | "ACE::netstat -antup | grep :443; ping 127.0.0.1; curl http://www.google.com", 47 | "PT:://///.htaccess", 48 | "PT::/etc/passwd", 49 | "PT::../../boot.ini", 50 | "PT::C:/inetpub/wwwroot/global.asa" 51 | ], 52 | "wafs": { 53 | "360": { 54 | "company": "360", 55 | "name": "360", 56 | "regex": "493|/wzws-waf-cgi/", 57 | "signatures": [ 58 | "9778:RVZXum61OEhCWapBYKcPk4JzWOpohM4JiUcMr2RXg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tKaK99n+i7c4VmkwI3FZjxtDtAeq+c36A5chW1XaTC", 59 | "9ccc:RVZXum61OEhCWapBYKcPk4JzWOpohM4JiUcMr2RXg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tKaK99n+i7c4VmkwI3FZjxtDtAeq+c36A4chW1XaTC" 60 | ] 61 | }, 62 | "aesecure": { 63 | "company": "aeSecure", 64 | "name": "aeSecure", 65 | "regex": "aesecure_denied\\.png|aesecure-code: \\d+", 66 | "signatures": [ 67 | "8a4b:RVdXu260OEhCWapBYKcPk4JzWOtohM4JiUcMrmRXg1uQJbX3uhdOn9htOj+hX7AB16FcPxJOdLsXo2tKaK99n+i7c4RmkgI2FZnxtDtBeq+c36A4chW1XaTD" 68 | ] 69 | }, 70 | "airlock": { 71 | "company": "Phion/Ergon", 72 | "name": "Airlock", 73 | "regex": "The server detected a syntax error in your request", 74 | "signatures": [ 75 | "3e2c:RVZXu261OEhCWapBYKcPk4JzWOtohM4IiUcMr2RXg1uQJbX3uhdOn9htOj+hX7AB16FcPxJPdLsXomtKaK59n+i6c4RmkwI2FZjxtDtAeq6c36A5chW1XaTD" 76 | ] 77 | }, 78 | "alertlogic": { 79 | "company": "Alert Logic", 80 | "name": "Alert Logic", 81 | "regex": "(?s)timed_redirect\\(seconds, url\\).+?

Reference ID:", 82 | "signatures": [] 83 | }, 84 | "aliyundun": { 85 | "company": "Alibaba Cloud Computing", 86 | "name": "AliYunDun", 87 | "regex": "Sorry, your request has been blocked as it may cause potential threats to the server's security|//errors\\.aliyun\\.com/", 88 | "signatures": [ 89 | "e082:RVZXum61OElCWapAYKYPkoJzWOpohM4JiUYMr2RXg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkgI2FZjxtDtAeq+c3qA4chW1XaTC" 90 | ] 91 | }, 92 | "anquanbao": { 93 | "company": "Anquanbao", 94 | "name": "Anquanbao", 95 | "regex": "/aqb_cc/error/", 96 | "signatures": [ 97 | "c790:RVZXum61OElCWapAYKYPk4JzWOpohM4JiUYMr2RXg1uQJbX3uhdOn9hsOj+hXrAB16FcPxJPdLsXo2tLaK99n+i7c4RmkgI2FZjxtDtAeq+c36A4chW1XaTC", 98 | "d3d3:RVZXum61OElCWapAYKYPk4JzWOpohM4JiUYMr2RXg1uQJbX3uhdOn9hsOj+hXrAB16FcPxJPdLsXo2tLaK99n+i7c4RmkgI2FZjxtDtAeq+c3qA4chW1XaTC" 99 | ] 100 | }, 101 | "approach": { 102 | "company": "Approach", 103 | "name": "Approach", 104 | "regex": "Approach.+?Web Application (Firewall|Filtering)", 105 | "signatures": [ 106 | "fef0:RVZXum60OEhCWKpAYKYPkoJyWOpohM4IiUYMrmRWg1qQJLX2uhZOnthsOj6hXrAA16BcPhJOdLoXomtKaK59nui7c4RmkgI2FZjxtDtAeq+c36A5chW1XKTD" 107 | ] 108 | }, 109 | "armor": { 110 | "company": "Armor Defense", 111 | "name": "Armor Protection", 112 | "regex": "This request has been blocked by website protection from Armor", 113 | "signatures": [ 114 | "03ec:RVZXum60OEhCWapBYKYPk4JzWOtohM4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tKaK99n+i6c4RmkgI2FZjxtDtAeq6c36A4chS1XaTC", 115 | "1160:RVZXum60OEhCWapBYKYPk4JyWOtohM4IiUcMr2RWg1qQJbX3uhZOnthsOj6hXrAA16BcPhJOdLoXo2tKaK99n+i6c4RmkgI2FZjxtDtAeq6c3qA4chS1XKTC" 116 | ], 117 | "note": "Uses SecureSphere (Imperva) (Reference: https://www.imperva.com/resources/case_studies/CS_Armor.pdf)" 118 | }, 119 | "asm": { 120 | "company": "F5 Networks", 121 | "name": "Application Security Manager", 122 | "regex": "The requested URL was rejected\\. Please consult with your administrator|security\\.f5aas\\.com", 123 | "signatures": [ 124 | "2f81:RVZXum60OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hXrAB16FcPxJPdLsXo2tLaK99n+i7c4RmkgI3FZjxtDtAeq+c36A4chS1XaTC", 125 | "4fd0:RVZXum60OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtDtAeq6c3qA4chS1XaTC", 126 | "5904:RVZXum60OEhCWapBYKcPk4JzWOpohc4IiUcMr2RWg1uQJbX3uhdOnthtOj+hXrAB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtTtAeq+c3qA4chS1XaTC", 127 | "8bcf:RVZXum60OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtTtAeq6c36A5chS1XaTC", 128 | "540f:RVZXum60OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtTtAeq+c36A5chS1XaTC", 129 | "c7ba:RVZXum60OEhCWKpAYKYPkoJzWOpohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXomtLaK99n+i7c4VmkwI3FZjxtDtAeq6c3qA4chS1XaTC", 130 | "fb21:RVZXum60OEhCWapBYKcPk4JzWOpohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkgI3FZjxtDtAeq+c36A5chW1XaTC", 131 | "b6ff:RVZXum61OEhCWapBYKcPkoJzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtDtAeq+c36A4chW1XaTC", 132 | "3b1e:RVZXum60OEhCWapBYKcPk4JyWOpohM4IiUcMr2RWg1qQJLX3uhdOnthtOj+hXrAB16FcPxJPdLsXo2tKaK99nui7c4RmkgI2FZjxtDtAeq6c3qA5chS1XKTC", 133 | "620c:RVZXum60OEhCWapBYKcPkoJzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkgI2FZjxtDtAeq+c36A5chW1XaTC", 134 | "b9a0:RVZXum60OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtDtAeq+c3qA4chW1XaTC", 135 | "ccb6:RVdXum61OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtTtAeq+c36A5chW1XaTC", 136 | "9138:RVZXum60OEhCWapBYKcPk4JzWOpohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtDtAeq6c3qA4chS1XaTC", 137 | "54cc:RVZXum61OEhCWapBYKcPkoJzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtDtAeq6c3qA4chS1XaTC", 138 | "4c83:RVZXum60OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4VmkwI3FZjxtDtAeq+c36A5chW1XaTC", 139 | "8453:RVZXum60OEhCWapBYKcPk4JzWOtohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPxJPdLsXo2tLaK99n+i7c4RmkwI3FZjxtDtAeq+c36A4chS1XaTC" 140 | ] 141 | }, 142 | "astra": { 143 | "company": "Czar Securities", 144 | "name": "Astra", 145 | "regex": "(?s)unfortunately our website protection system.+?//www\\.getastra\\.com", 146 | "signatures": [] 147 | }, 148 | "aws": { 149 | "company": "Amazon", 150 | "name": "AWS WAF", 151 | "regex": "(?i)HTTP/1.+\\b403\\b.+\\s+Server: aws|(?s)Request blocked.+?Generated by cloudfront", 152 | "signatures": [ 153 | "2998:RVZXu261OEhCWapBYKcPk4JzWOpohM4IiUcMr2RWg1uQJbX3uhZOnthsOj6hXrAA16BcPhJOdLoXo2tKaK99n+i6c4RmkgI2FZjxtDtAeq6c3qA4chS1XKTC", 154 | "fffa:RVZXum60OEhCWapAYKYPk4JyWOpohc4JiUcMr2RWg1uQJbX3uhdOnthtOj+hX7AB16FcPhJPdLsXo2tKaK99n+i6c4RmkgI2FZjxtDtAeq6c3qA4chS1XKTC", 155 | "9de0:RVZXu261OEhCWapBYKcPk4JzWOpohM4IiUcMr2RWg1uQJbX3uhZOnthtOj+hXrAA16BcPhJOdLoXo2tKaK99n+i7c4RmkgI2FZjxtDtAeq6c3qA4chS1XKTC", 156 | "34a8:RVZXu261OEhCWapBYKcPk4JzWOpohM4IiUcMr2RWg1uQJbX3uhdOn9htOj+hXrAB16BcPxJOdLsXo2tKaK99n+i7c4RmkgI2FZjxtDtAeq6c3qA4chS1XKTC", 157 | "1104:RVZXum61OEhCWapBYKcPk4JzWOpohM4IiUcMr2RXg1uQJbX3uhZOnthsOj6hXrAA16BcPhJOdLoXomtKaK59n+i6c4RmkgI2FZjxtDtAeq6c3qA4chS1XKTC", 158 | "ea40:RVZXu261OEhCWapBYKcPk4JzWOtohM4IiUcMr2RWg1uQJbX3uhdOn9htOj+hXrAB16BcPxJOdLsXo2tKaK99n+i7c4RmkgI2FZjxtDtAeq6c3qA4chS1XKTC" 159 | ] 160 | }, 161 | "barracuda": { 162 | "company": "Barracuda Networks", 163 | "name": "Barracuda", 164 | "regex": "\\bbarracuda_|barra_counter_session=|when this page occurred and the event ID found at the bottom of the page|||<[^>]+>|\s+", " ", retval[HTML]) 181 | match = re.search(r"(?im)^Server: (.+)", retval[RAW]) 182 | retval[SERVER] = match.group(1).strip() if match else "" 183 | return retval 184 | 185 | def calc_hash(value, binary=True): 186 | value = value.encode("utf8") if not isinstance(value, bytes) else value 187 | result = zlib.crc32(value) & 0xffff 188 | if binary: 189 | result = struct.pack(">H", result) 190 | return result 191 | 192 | def single_print(message): 193 | if message not in seen: 194 | print(message) 195 | seen.add(message) 196 | 197 | def check_payload(payload, protection_regex=GENERIC_PROTECTION_REGEX % '|'.join(GENERIC_PROTECTION_KEYWORDS)): 198 | global chained 199 | global heuristic 200 | global intrusive 201 | global locked_code 202 | global locked_regex 203 | 204 | time.sleep(options.delay or 0) 205 | if options.post: 206 | _ = "%s=%s" % ("".join(random.sample(string.ascii_letters, 3)), quote(payload)) 207 | intrusive = retrieve(options.url, _) 208 | else: 209 | _ = "%s%s%s=%s" % (options.url, '?' if '?' not in options.url else '&', "".join(random.sample(string.ascii_letters, 3)), quote(payload)) 210 | intrusive = retrieve(_) 211 | 212 | if options.lock and not payload.isdigit(): 213 | if payload == HEURISTIC_PAYLOAD: 214 | match = re.search(re.sub(r"Server:|Protected by", "".join(random.sample(string.ascii_letters, 6)), WAF_RECOGNITION_REGEX, flags=re.I), intrusive[RAW] or "") 215 | if match: 216 | result = True 217 | 218 | for _ in match.groupdict(): 219 | if match.group(_): 220 | waf = re.sub(r"\Awaf_", "", _) 221 | locked_regex = DATA_JSON["wafs"][waf]["regex"] 222 | locked_code = intrusive[HTTPCODE] 223 | break 224 | else: 225 | result = False 226 | 227 | if not result: 228 | exit(colorize("[x] can't lock results to a non-blind match")) 229 | else: 230 | result = re.search(locked_regex, intrusive[RAW]) is not None and locked_code == intrusive[HTTPCODE] 231 | elif options.string: 232 | result = options.string in (intrusive[RAW] or "") 233 | elif options.code: 234 | result = options.code == intrusive[HTTPCODE] 235 | else: 236 | result = intrusive[HTTPCODE] != original[HTTPCODE] or (intrusive[HTTPCODE] != 200 and intrusive[TITLE] != original[TITLE]) or (re.search(protection_regex, intrusive[HTML]) is not None and re.search(protection_regex, original[HTML]) is None) or (difflib.SequenceMatcher(a=original[HTML] or "", b=intrusive[HTML] or "").quick_ratio() < QUICK_RATIO_THRESHOLD) 237 | 238 | if not payload.isdigit(): 239 | if result: 240 | if options.debug: 241 | print("\r---%s" % (40 * ' ')) 242 | print(payload) 243 | print(intrusive[HTTPCODE], intrusive[RAW]) 244 | print("---") 245 | 246 | if intrusive[SERVER]: 247 | servers.add(re.sub(r"\s*\(.+\)\Z", "", intrusive[SERVER])) 248 | if len(servers) > 1: 249 | chained = True 250 | single_print(colorize("[!] multiple (reactive) rejection HTTP 'Server' headers detected (%s)" % ', '.join("'%s'" % _ for _ in sorted(servers)))) 251 | 252 | if intrusive[HTTPCODE]: 253 | codes.add(intrusive[HTTPCODE]) 254 | if len(codes) > 1: 255 | chained = True 256 | single_print(colorize("[!] multiple (reactive) rejection HTTP codes detected (%s)" % ', '.join("%s" % _ for _ in sorted(codes)))) 257 | 258 | if heuristic and heuristic[HTML] and intrusive[HTML] and difflib.SequenceMatcher(a=heuristic[HTML] or "", b=intrusive[HTML] or "").quick_ratio() < QUICK_RATIO_THRESHOLD: 259 | chained = True 260 | single_print(colorize("[!] multiple (reactive) rejection HTML responses detected")) 261 | 262 | if payload == HEURISTIC_PAYLOAD: 263 | heuristic = intrusive 264 | 265 | return result 266 | 267 | def colorize(message): 268 | if COLORIZE: 269 | message = re.sub(r"\[(.)\]", lambda match: "[%s%s\033[00;49m]" % (LEVEL_COLORS[match.group(1)], match.group(1)), message) 270 | 271 | if any(_ in message for _ in ("rejected summary", "challenge detected")): 272 | for match in re.finditer(r"[^\w]'([^)]+)'" if "rejected summary" in message else r"\('(.+)'\)", message): 273 | message = message.replace("'%s'" % match.group(1), "'\033[37m%s\033[00;49m'" % match.group(1), 1) 274 | else: 275 | for match in re.finditer(r"[^\w]'([^']+)'", message): 276 | message = message.replace("'%s'" % match.group(1), "'\033[37m%s\033[00;49m'" % match.group(1), 1) 277 | 278 | if "blind match" in message: 279 | for match in re.finditer(r"\(((\d+)%)\)", message): 280 | message = message.replace(match.group(1), "\033[%dm%s\033[00;49m" % (92 if int(match.group(2)) >= 95 else (93 if int(match.group(2)) > 80 else 90), match.group(1))) 281 | 282 | if "hardness" in message: 283 | for match in re.finditer(r"\(((\d+)%)\)", message): 284 | message = message.replace(match.group(1), "\033[%dm%s\033[00;49m" % (95 if " insane " in message else (91 if " hard " in message else (93 if " moderate " in message else 92)), match.group(1))) 285 | 286 | return message 287 | 288 | def parse_args(): 289 | global options 290 | 291 | parser = optparse.OptionParser(version=VERSION) 292 | parser.add_option("--delay", dest="delay", type=int, help="Delay (sec) between tests (default: 0)") 293 | parser.add_option("--timeout", dest="timeout", type=int, help="Response timeout (sec) (default: 10)") 294 | parser.add_option("--proxy", dest="proxy", help="HTTP proxy address (e.g. \"http://127.0.0.1:8080\")") 295 | parser.add_option("--proxy-file", dest="proxy_file", help="Load (rotating) HTTP(s) proxy list from a file") 296 | parser.add_option("--random-agent", dest="random_agent", action="store_true", help="Use random HTTP User-Agent header value") 297 | parser.add_option("--code", dest="code", type=int, help="Expected HTTP code in rejected responses") 298 | parser.add_option("--string", dest="string", help="Expected string in rejected responses") 299 | parser.add_option("--post", dest="post", action="store_true", help="Use POST body for sending payloads") 300 | parser.add_option("--debug", dest="debug", action="store_true", help=optparse.SUPPRESS_HELP) 301 | parser.add_option("--fast", dest="fast", action="store_true", help=optparse.SUPPRESS_HELP) 302 | parser.add_option("--lock", dest="lock", action="store_true", help=optparse.SUPPRESS_HELP) 303 | 304 | # Dirty hack(s) for help message 305 | def _(self, *args): 306 | retval = parser.formatter._format_option_strings(*args) 307 | if len(retval) > MAX_HELP_OPTION_LENGTH: 308 | retval = ("%%.%ds.." % (MAX_HELP_OPTION_LENGTH - parser.formatter.indent_increment)) % retval 309 | return retval 310 | 311 | parser.usage = "python %s " % parser.usage 312 | parser.formatter._format_option_strings = parser.formatter.format_option_strings 313 | parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser) 314 | 315 | for _ in ("-h", "--version"): 316 | option = parser.get_option(_) 317 | option.help = option.help.capitalize() 318 | 319 | try: 320 | options, _ = parser.parse_args() 321 | except SystemExit: 322 | raise 323 | 324 | if len(sys.argv) > 1: 325 | url = sys.argv[-1] 326 | if not url.startswith("http"): 327 | url = "http://%s" % url 328 | options.url = url 329 | else: 330 | parser.print_help() 331 | raise SystemExit 332 | 333 | for key in DEFAULTS: 334 | if getattr(options, key, None) is None: 335 | setattr(options, key, DEFAULTS[key]) 336 | 337 | def load_data(): 338 | global WAF_RECOGNITION_REGEX 339 | 340 | if os.path.isfile(DATA_JSON_FILE): 341 | with codecs.open(DATA_JSON_FILE, "rb", encoding="utf8") as f: 342 | DATA_JSON.update(json.load(f)) 343 | 344 | WAF_RECOGNITION_REGEX = "" 345 | for waf in DATA_JSON["wafs"]: 346 | if DATA_JSON["wafs"][waf]["regex"]: 347 | WAF_RECOGNITION_REGEX += "%s|" % ("(?P%s)" % (waf, DATA_JSON["wafs"][waf]["regex"])) 348 | for signature in DATA_JSON["wafs"][waf]["signatures"]: 349 | SIGNATURES[signature] = waf 350 | WAF_RECOGNITION_REGEX = WAF_RECOGNITION_REGEX.strip('|') 351 | 352 | flags = "".join(set(_ for _ in "".join(re.findall(r"\(\?(\w+)\)", WAF_RECOGNITION_REGEX)))) 353 | WAF_RECOGNITION_REGEX = "(?%s)%s" % (flags, re.sub(r"\(\?\w+\)", "", WAF_RECOGNITION_REGEX)) # patch for "DeprecationWarning: Flags not at the start of the expression" in Python3.7 354 | else: 355 | exit(colorize("[x] file '%s' is missing" % DATA_JSON_FILE)) 356 | 357 | def init(): 358 | os.chdir(os.path.abspath(os.path.dirname(__file__))) 359 | 360 | # Reference: http://blog.mathieu-leplatre.info/python-utf-8-print-fails-when-redirecting-stdout.html 361 | if not PY3 and not IS_TTY: 362 | sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout) 363 | 364 | print(colorize("[o] initializing handlers...")) 365 | 366 | # Reference: https://stackoverflow.com/a/28052583 367 | if hasattr(ssl, "_create_unverified_context"): 368 | ssl._create_default_https_context = ssl._create_unverified_context 369 | 370 | if options.proxy_file: 371 | if os.path.isfile(options.proxy_file): 372 | print(colorize("[o] loading proxy list...")) 373 | 374 | with codecs.open(options.proxy_file, "rb", encoding="utf8") as f: 375 | proxies.extend(re.sub(r"\s.*", "", _.strip()) for _ in f.read().strip().split('\n') if _.startswith("http")) 376 | random.shuffle(proxies) 377 | else: 378 | exit(colorize("[x] file '%s' does not exist" % options.proxy_file)) 379 | 380 | 381 | cookie_jar = CookieJar() 382 | opener = build_opener(HTTPCookieProcessor(cookie_jar)) 383 | install_opener(opener) 384 | 385 | if options.proxy: 386 | opener = build_opener(ProxyHandler({"http": options.proxy, "https": options.proxy})) 387 | install_opener(opener) 388 | 389 | if options.random_agent: 390 | revision = random.randint(20, 64) 391 | platform = random.sample(("X11; %s %s" % (random.sample(("Linux", "Ubuntu; Linux", "U; Linux", "U; OpenBSD", "U; FreeBSD"), 1)[0], random.sample(("amd64", "i586", "i686", "amd64"), 1)[0]), "Windows NT %s%s" % (random.sample(("5.0", "5.1", "5.2", "6.0", "6.1", "6.2", "6.3", "10.0"), 1)[0], random.sample(("", "; Win64", "; WOW64"), 1)[0]), "Macintosh; Intel Mac OS X 10.%s" % random.randint(1, 11)), 1)[0] 392 | user_agent = "Mozilla/5.0 (%s; rv:%d.0) Gecko/20100101 Firefox/%d.0" % (platform, revision, revision) 393 | HEADERS["User-Agent"] = user_agent 394 | 395 | def format_name(waf): 396 | 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 "") 397 | 398 | def non_blind_check(raw, silent=False): 399 | retval = False 400 | match = re.search(WAF_RECOGNITION_REGEX, raw or "") 401 | if match: 402 | retval = True 403 | for _ in match.groupdict(): 404 | if match.group(_): 405 | waf = re.sub(r"\Awaf_", "", _) 406 | non_blind.add(waf) 407 | if not silent: 408 | single_print(colorize("[+] non-blind match: '%s'%s" % (format_name(waf), 20 * ' '))) 409 | return retval 410 | 411 | def run(): 412 | global original 413 | 414 | hostname = options.url.split("//")[-1].split('/')[0].split(':')[0] 415 | 416 | if not hostname.replace('.', "").isdigit(): 417 | print(colorize("[i] checking hostname '%s'..." % hostname)) 418 | try: 419 | socket.getaddrinfo(hostname, None) 420 | except socket.gaierror: 421 | exit(colorize("[x] host '%s' does not exist" % hostname)) 422 | 423 | results = "" 424 | signature = b"" 425 | counter = 0 426 | original = retrieve(options.url) 427 | 428 | if 300 <= (original[HTTPCODE] or 0) < 400 and original[URL]: 429 | original = retrieve(original[URL]) 430 | 431 | options.url = original[URL] 432 | 433 | if original[HTTPCODE] is None: 434 | exit(colorize("[x] missing valid response")) 435 | 436 | if not any((options.string, options.code)) and original[HTTPCODE] >= 400: 437 | non_blind_check(original[RAW]) 438 | if options.debug: 439 | print("\r---%s" % (40 * ' ')) 440 | print(original[HTTPCODE], original[RAW]) 441 | print("---") 442 | exit(colorize("[x] access to host '%s' seems to be restricted%s" % (hostname, (" (%d: '%s')" % (original[HTTPCODE], original[TITLE].strip())) if original[TITLE] else ""))) 443 | 444 | challenge = None 445 | if all(_ in original[HTML].lower() for _ in ("eval", "]*>(.*)", re.sub(r"(?is)", "", original[HTML])) 447 | if re.search(r"(?i)<(body|div)", original[HTML]) is None or (match and len(match.group(1)) == 0): 448 | challenge = re.search(r"(?is)", original[HTML]).group(0).replace("\n", "\\n") 449 | print(colorize("[x] anti-robot JS challenge detected ('%s%s')" % (challenge[:MAX_JS_CHALLENGE_SNAPLEN], "..." if len(challenge) > MAX_JS_CHALLENGE_SNAPLEN else ""))) 450 | 451 | protection_keywords = GENERIC_PROTECTION_KEYWORDS 452 | protection_regex = GENERIC_PROTECTION_REGEX % '|'.join(keyword for keyword in protection_keywords if keyword not in original[HTML].lower()) 453 | 454 | print(colorize("[i] running basic heuristic test...")) 455 | if not check_payload(HEURISTIC_PAYLOAD): 456 | check = False 457 | if options.url.startswith("https://"): 458 | options.url = options.url.replace("https://", "http://") 459 | check = check_payload(HEURISTIC_PAYLOAD) 460 | if not check: 461 | if non_blind_check(intrusive[RAW]): 462 | exit(colorize("[x] unable to continue due to static responses%s" % (" (captcha)" if re.search(r"(?i)captcha", intrusive[RAW]) is not None else ""))) 463 | elif challenge is None: 464 | exit(colorize("[x] host '%s' does not seem to be protected" % hostname)) 465 | else: 466 | exit(colorize("[x] response not changing without JS challenge solved")) 467 | 468 | if options.fast and not non_blind: 469 | exit(colorize("[x] fast exit because of missing non-blind match")) 470 | 471 | if not intrusive[HTTPCODE]: 472 | print(colorize("[i] rejected summary: RST|DROP")) 473 | else: 474 | _ = "...".join(match.group(0) for match in re.finditer(GENERIC_ERROR_MESSAGE_REGEX, intrusive[HTML])).strip().replace(" ", " ") 475 | print(colorize(("[i] rejected summary: %d ('%s%s')" % (intrusive[HTTPCODE], ("%s" % intrusive[TITLE]) if intrusive[TITLE] else "", "" if not _ or intrusive[HTTPCODE] < 400 else ("...%s" % _))).replace(" ('')", ""))) 476 | 477 | found = non_blind_check(intrusive[RAW] if intrusive[HTTPCODE] is not None else original[RAW]) 478 | 479 | if not found: 480 | print(colorize("[-] non-blind match: -")) 481 | 482 | for item in DATA_JSON["payloads"]: 483 | info, payload = item.split("::", 1) 484 | counter += 1 485 | 486 | if IS_TTY: 487 | sys.stdout.write(colorize("\r[i] running payload tests... (%d/%d)\r" % (counter, len(DATA_JSON["payloads"])))) 488 | sys.stdout.flush() 489 | 490 | if counter % VERIFY_OK_INTERVAL == 0: 491 | for i in xrange(VERIFY_RETRY_TIMES): 492 | if not check_payload(str(random.randint(1, 9)), protection_regex): 493 | break 494 | elif i == VERIFY_RETRY_TIMES - 1: 495 | exit(colorize("[x] host '%s' seems to be misconfigured or rejecting benign requests%s" % (hostname, (" (%d: '%s')" % (intrusive[HTTPCODE], intrusive[TITLE].strip())) if intrusive[TITLE] else ""))) 496 | else: 497 | time.sleep(5) 498 | 499 | last = check_payload(payload, protection_regex) 500 | non_blind_check(intrusive[RAW]) 501 | signature += struct.pack(">H", ((calc_hash(payload, binary=False) << 1) | last) & 0xffff) 502 | results += 'x' if last else '.' 503 | 504 | if last and info not in blocked: 505 | blocked.append(info) 506 | 507 | _ = calc_hash(signature) 508 | signature = "%s:%s" % (_.encode("hex") if not hasattr(_, "hex") else _.hex(), base64.b64encode(signature).decode("ascii")) 509 | 510 | print(colorize("%s[=] results: '%s'" % ("\n" if IS_TTY else "", results))) 511 | 512 | hardness = 100 * results.count('x') // len(results) 513 | print(colorize("[=] hardness: %s (%d%%)" % ("insane" if hardness >= 80 else ("hard" if hardness >= 50 else ("moderate" if hardness >= 30 else "easy")), hardness))) 514 | 515 | if blocked: 516 | print(colorize("[=] blocked categories: %s" % ", ".join(blocked))) 517 | 518 | if not results.strip('.') or not results.strip('x'): 519 | print(colorize("[-] blind match: -")) 520 | 521 | if re.search(r"(?i)captcha", original[HTML]) is not None: 522 | exit(colorize("[x] there seems to be an activated captcha")) 523 | else: 524 | print(colorize("[=] signature: '%s'" % signature)) 525 | 526 | if signature in SIGNATURES: 527 | waf = SIGNATURES[signature] 528 | print(colorize("[+] blind match: '%s' (100%%)" % format_name(waf))) 529 | elif results.count('x') < MIN_MATCH_PARTIAL: 530 | print(colorize("[-] blind match: -")) 531 | else: 532 | matches = {} 533 | markers = set() 534 | decoded = base64.b64decode(signature.split(':')[-1]) 535 | for i in xrange(0, len(decoded), 2): 536 | part = struct.unpack(">H", decoded[i: i + 2])[0] 537 | markers.add(part) 538 | 539 | for candidate in SIGNATURES: 540 | counter_y, counter_n = 0, 0 541 | decoded = base64.b64decode(candidate.split(':')[-1]) 542 | for i in xrange(0, len(decoded), 2): 543 | part = struct.unpack(">H", decoded[i: i + 2])[0] 544 | if part in markers: 545 | counter_y += 1 546 | elif any(_ in markers for _ in (part & ~1, part | 1)): 547 | counter_n += 1 548 | result = int(round(100.0 * counter_y / (counter_y + counter_n))) 549 | if SIGNATURES[candidate] in matches: 550 | if result > matches[SIGNATURES[candidate]]: 551 | matches[SIGNATURES[candidate]] = result 552 | else: 553 | matches[SIGNATURES[candidate]] = result 554 | 555 | if chained: 556 | for _ in list(matches.keys()): 557 | if matches[_] < 90: 558 | del matches[_] 559 | 560 | if not matches: 561 | print(colorize("[-] blind match: - ")) 562 | print(colorize("[!] probably chained web protection systems")) 563 | else: 564 | matches = [(_[1], _[0]) for _ in matches.items()] 565 | matches.sort(reverse=True) 566 | 567 | print(colorize("[+] blind match: %s" % ", ".join("'%s' (%d%%)" % (format_name(matches[i][1]), matches[i][0]) for i in xrange(min(len(matches), MAX_MATCHES) if matches[0][0] != 100 else 1)))) 568 | 569 | print() 570 | 571 | def main(): 572 | if "--version" not in sys.argv: 573 | print(BANNER) 574 | 575 | parse_args() 576 | init() 577 | run() 578 | 579 | load_data() 580 | 581 | if __name__ == "__main__": 582 | try: 583 | main() 584 | except KeyboardInterrupt: 585 | exit(colorize("\r[x] Ctrl-C pressed")) 586 | -------------------------------------------------------------------------------- /screenshots/360.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/360.png -------------------------------------------------------------------------------- /screenshots/aesecure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/aesecure.png -------------------------------------------------------------------------------- /screenshots/airlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/airlock.png -------------------------------------------------------------------------------- /screenshots/alertlogic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/alertlogic.png -------------------------------------------------------------------------------- /screenshots/aliyundun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/aliyundun.png -------------------------------------------------------------------------------- /screenshots/anquanbao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/anquanbao.png -------------------------------------------------------------------------------- /screenshots/approach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/approach.png -------------------------------------------------------------------------------- /screenshots/armor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/armor.png -------------------------------------------------------------------------------- /screenshots/asm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/asm.png -------------------------------------------------------------------------------- /screenshots/astra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/astra.png -------------------------------------------------------------------------------- /screenshots/aws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/aws.png -------------------------------------------------------------------------------- /screenshots/barracuda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/barracuda.png -------------------------------------------------------------------------------- /screenshots/bekchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/bekchy.png -------------------------------------------------------------------------------- /screenshots/bitninja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/bitninja.png -------------------------------------------------------------------------------- /screenshots/bluedon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/bluedon.png -------------------------------------------------------------------------------- /screenshots/bulletproof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/bulletproof.png -------------------------------------------------------------------------------- /screenshots/cdnns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/cdnns.png -------------------------------------------------------------------------------- /screenshots/cerber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/cerber.png -------------------------------------------------------------------------------- /screenshots/chuangyu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/chuangyu.png -------------------------------------------------------------------------------- /screenshots/cloudbric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/cloudbric.png -------------------------------------------------------------------------------- /screenshots/cloudflare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/cloudflare.png -------------------------------------------------------------------------------- /screenshots/cloudfront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/cloudfront.png -------------------------------------------------------------------------------- /screenshots/comodo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/comodo.png -------------------------------------------------------------------------------- /screenshots/crawlprotect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/crawlprotect.png -------------------------------------------------------------------------------- /screenshots/distil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/distil.png -------------------------------------------------------------------------------- /screenshots/dotdefender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/dotdefender.png -------------------------------------------------------------------------------- /screenshots/duedge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/duedge.png -------------------------------------------------------------------------------- /screenshots/expressionengine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/expressionengine.png -------------------------------------------------------------------------------- /screenshots/fortiweb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/fortiweb.png -------------------------------------------------------------------------------- /screenshots/godaddy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/godaddy.png -------------------------------------------------------------------------------- /screenshots/greywizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/greywizard.png -------------------------------------------------------------------------------- /screenshots/gtmc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/gtmc.png -------------------------------------------------------------------------------- /screenshots/imunify360.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/imunify360.png -------------------------------------------------------------------------------- /screenshots/incapsula.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/incapsula.png -------------------------------------------------------------------------------- /screenshots/janusec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/janusec.png -------------------------------------------------------------------------------- /screenshots/jiasule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/jiasule.png -------------------------------------------------------------------------------- /screenshots/kona.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/kona.png -------------------------------------------------------------------------------- /screenshots/kuipernet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/kuipernet.png -------------------------------------------------------------------------------- /screenshots/malcare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/malcare.png -------------------------------------------------------------------------------- /screenshots/modsecurity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/modsecurity.png -------------------------------------------------------------------------------- /screenshots/naxsi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/naxsi.png -------------------------------------------------------------------------------- /screenshots/netscaler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/netscaler.png -------------------------------------------------------------------------------- /screenshots/newdefend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/newdefend.png -------------------------------------------------------------------------------- /screenshots/nexusguard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/nexusguard.png -------------------------------------------------------------------------------- /screenshots/ninjafirewall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/ninjafirewall.png -------------------------------------------------------------------------------- /screenshots/onmessageshield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/onmessageshield.png -------------------------------------------------------------------------------- /screenshots/openrasp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/openrasp.png -------------------------------------------------------------------------------- /screenshots/paloalto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/paloalto.png -------------------------------------------------------------------------------- /screenshots/profense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/profense.png -------------------------------------------------------------------------------- /screenshots/radware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/radware.png -------------------------------------------------------------------------------- /screenshots/reblaze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/reblaze.png -------------------------------------------------------------------------------- /screenshots/requestvalidationmode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/requestvalidationmode.png -------------------------------------------------------------------------------- /screenshots/rsfirewall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/rsfirewall.png -------------------------------------------------------------------------------- /screenshots/safe3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/safe3.png -------------------------------------------------------------------------------- /screenshots/safedog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/safedog.png -------------------------------------------------------------------------------- /screenshots/safeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/safeline.png -------------------------------------------------------------------------------- /screenshots/secupress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/secupress.png -------------------------------------------------------------------------------- /screenshots/secureentry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/secureentry.png -------------------------------------------------------------------------------- /screenshots/secureiis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/secureiis.png -------------------------------------------------------------------------------- /screenshots/securesphere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/securesphere.png -------------------------------------------------------------------------------- /screenshots/shieldsecurity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/shieldsecurity.png -------------------------------------------------------------------------------- /screenshots/siteground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/siteground.png -------------------------------------------------------------------------------- /screenshots/siteguard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/siteguard.png -------------------------------------------------------------------------------- /screenshots/sitelock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/sitelock.png -------------------------------------------------------------------------------- /screenshots/sonicwall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/sonicwall.png -------------------------------------------------------------------------------- /screenshots/squarespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/squarespace.png -------------------------------------------------------------------------------- /screenshots/stackpath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/stackpath.png -------------------------------------------------------------------------------- /screenshots/sucuri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/sucuri.png -------------------------------------------------------------------------------- /screenshots/tencent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/tencent.png -------------------------------------------------------------------------------- /screenshots/urlmaster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/urlmaster.png -------------------------------------------------------------------------------- /screenshots/urlscan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/urlscan.png -------------------------------------------------------------------------------- /screenshots/vercel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/vercel.png -------------------------------------------------------------------------------- /screenshots/virusdie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/virusdie.png -------------------------------------------------------------------------------- /screenshots/vsf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/vsf.png -------------------------------------------------------------------------------- /screenshots/wallarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/wallarm.png -------------------------------------------------------------------------------- /screenshots/watchguard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/watchguard.png -------------------------------------------------------------------------------- /screenshots/webarx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/webarx.png -------------------------------------------------------------------------------- /screenshots/webknight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/webknight.png -------------------------------------------------------------------------------- /screenshots/webland.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/webland.png -------------------------------------------------------------------------------- /screenshots/wordfence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/wordfence.png -------------------------------------------------------------------------------- /screenshots/wts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/wts.png -------------------------------------------------------------------------------- /screenshots/yundun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/yundun.png -------------------------------------------------------------------------------- /screenshots/yunsuo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/yunsuo.png -------------------------------------------------------------------------------- /screenshots/zenedge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stamparm/identYwaf/ae7e44ae8da6f01be3f63d7edfe6ea77240ff42c/screenshots/zenedge.png --------------------------------------------------------------------------------