diff -Nru wafw00f-2.0.0/debian/changelog wafw00f-2.1.0/debian/changelog --- wafw00f-2.0.0/debian/changelog 2019-12-15 23:37:57.000000000 +0000 +++ wafw00f-2.1.0/debian/changelog 2020-02-06 20:51:18.000000000 +0000 @@ -1,3 +1,9 @@ +wafw00f (2.1.0-1) unstable; urgency=medium + + * New upstream version 2.1.0 + + -- Samuel Henrique Thu, 06 Feb 2020 21:51:18 +0100 + wafw00f (2.0.0-1) unstable; urgency=medium * New upstream version 2.0.0 diff -Nru wafw00f-2.0.0/debian/control wafw00f-2.1.0/debian/control --- wafw00f-2.0.0/debian/control 2019-12-15 23:37:57.000000000 +0000 +++ wafw00f-2.1.0/debian/control 2020-02-06 20:51:18.000000000 +0000 @@ -9,7 +9,7 @@ python3-all, python3-pluginbase, python3-setuptools -Standards-Version: 4.4.1 +Standards-Version: 4.5.0 Rules-Requires-Root: no Testsuite: autopkgtest-pkg-python Homepage: https://github.com/sandrogauci/wafw00f diff -Nru wafw00f-2.0.0/docs/wafw00f.8 wafw00f-2.1.0/docs/wafw00f.8 --- wafw00f-2.0.0/docs/wafw00f.8 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/docs/wafw00f.8 2020-01-29 12:24:09.000000000 +0000 @@ -29,6 +29,12 @@ \fB\-t\fR WAF, \fB\-\-test\fR=\fI\,WAF\/\fR Test for one specific WAF product. .TP +\fB\-o\fR OUTPUT, \fB\-\-output\fR=\fI\,OUTPUT\/\fR +Write output to csv, json or text file depending on file extension. For stdout, specify - as filename. +.TP +\fB\-i\fR INPUT, \fB\-\-input\fR=\fI\,INPUT\/\fR +Read targets from a file. Input format can be csv, json or text. For csv and json, a `url` column name or element is required. +.TP \fB\-l\fR, \fB\-\-list\fR List all the WAFs that WAFW00F is able to detect. .TP diff -Nru wafw00f-2.0.0/README.md wafw00f-2.1.0/README.md --- wafw00f-2.0.0/README.md 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/README.md 2020-01-29 12:24:09.000000000 +0000 @@ -46,165 +46,177 @@ ``` $ wafw00f -l - - ______ - / \ - ( W00f! ) - \ ____/ - ,, __ 404 Hack Not Found - |`-.__ / / __ __ - /" _/ /_/ \ \ / / - *===* / \ \_/ / 405 Not Allowed - / )__// \ / - /| / /---` 403 Forbidden - \\/` \ | / _ \ - `\ /_\\_ 502 Bad Gateway / / \ \ 500 Internal Error - `_____``-` /_/ \_\ - - ~ WAFW00F : v2.0.0 ~ - The Web Application Firewall Fingerprinting Toolkit + ______ + / \ + ( Woof! ) + \ ____/ ) + ,, ) (_ + .-. - _______ ( |__| + ()``; |==|_______) .)|__| + / (' /|\ ( |__| + ( / ) / | \ . |__| + \(_)_)) / | \ |__| + ~ WAFW00F : v2.1.0 ~ + The Web Application Firewall Fingerprinting Toolkit + [+] Can test for these WAFs: - WAF Name Manufacturer - -------- ------------ + WAF Name Manufacturer + -------- ------------ - ACE XML Gateway Cisco - aeSecure aeSecure - AireeCDN Airee - Airlock Phion/Ergon - Alert Logic Alert Logic - AliYunDun Alibaba Cloud Computing - Anquanbao Anquanbao - AnYu AnYu Technologies - Approach Approach - AppWall Radware - Armor Defense Armor - ArvanCloud ArvanCloud - ASP.NET Generic Microsoft - ASPA Firewall ASPA Engineering Co. - Astra Czar Securities - AzionCDN AzionCDN - Barikode Ethic Ninja - Barracuda Barracuda Networks - Bekchy Faydata Technologies Inc. - Beluga CDN Beluga - BinarySec BinarySec - BitNinja BitNinja - BlockDoS BlockDoS - Bluedon Bluedon IST - CacheWall Varnish - CacheFly CDN CacheFly - Comodo cWatch Comodo CyberSecurity - Chuang Yu Shield Yunaq - Cloudbric Penta Security - Cloudflare Cloudflare Inc. - Cloudfloor Cloudfloor DNS - Cloudfront Amazon - CrawlProtect Jean-Denis Brun - DataPower IBM - DenyALL Rohde & Schwarz CyberSecurity - Distil Distil Networks - DOSarrest DOSarrest Internet Security - DotDefender Applicure Technologies - Edgecast Verizon Digital Media - Eisoo Cloud Firewall Eisoo - Expression Engine EllisLab - BIG-IP AppSec Manager F5 Networks - BIG-IP AP Manager F5 Networks - Fastly Fastly CDN - FirePass F5 Networks - FortiWeb Fortinet - Greywizard Grey Wizard - Huawei Cloud Firewall Huawei - HyperGuard Art of Defense - Imunify360 CloudLinux - Incapsula Imperva Inc. - IndusGuard Indusface - Instart DX Instart Logic - ISA Server Microsoft - Jiasule Jiasule - Kona SiteDefender Akamai - KS-WAF KnownSec - KeyCDN KeyCDN - LimeLight CDN LimeLight - LiteSpeed LiteSpeed Technologies - Open-Resty Lua Nginx FLOSS - Oracle Cloud Oracle - Malcare Inactiv - MaxCDN MaxCDN - ModSecurity SpiderLabs - NAXSI NBS Systems - Nemesida PentestIt - NevisProxy AdNovum - NetContinuum Barracuda Networks - NetScaler AppFirewall Citrix Systems - Newdefend NewDefend - NexusGuard Firewall NexusGuard - NinjaFirewall NinTechNet - NullDDoS Protection NullDDoS - NSFocus NSFocus Global Inc. - OnMessage Shield BlackBaud - PerimeterX PerimeterX - PentaWAF Global Network Services - pkSecurity IDS pkSec - PowerCDN PowerCDN - Profense ArmorLogic - Puhui Puhui - Qiniu Qiniu CDN - Reblaze Reblaze - RSFirewall RSJoomla! - Sabre Firewall Sabre - Safe3 Web Firewall Safe3 - Safedog SafeDog - Safeline Chaitin Tech. - SecKing SecKing - eEye SecureIIS BeyondTrust - SecuPress WP Security SecuPress - SecureSphere Imperva Inc. - Secure Entry United Security Providers - SEnginx Neusoft - ServerDefender VP Port80 Software - Shield Security One Dollar Plugin - Shadow Daemon Zecure - SiteGround SiteGround - SiteGuard Sakura Inc. - Sitelock TrueShield - SonicWall Dell - UTM Web Protection Sophos - Squarespace Squarespace - SquidProxy IDS SquidProxy - StackPath StackPath - Sucuri CloudProxy Sucuri Inc. - Teros Citrix Systems - Trafficshield F5 Networks - TransIP Web Firewall TransIP - URLScan Microsoft - UEWaf UCloud - Varnish OWASP - Viettel Cloudrity - VirusDie VirusDie LLC - Wallarm Wallarm Inc. - WatchGuard WatchGuard Technologies - WebARX WebARX Security Solutions - WebKnight AQTRONIX - WebLand WebLand - RayWAF WebRay Solutions - WebSEAL IBM - WebTotem WebTotem - West263 CDN West263CDN - Wordfence Defiant - WP Cerber Security Cerber Tech - WTS-WAF WTS - 360WangZhanBao 360 Technologies - XLabs Security WAF XLabs - Xuanwudun Xuanwudun - Yundun Yundun - Yunsuo Yunsuo - Yunjiasu Baidu Cloud Computing - YXLink YxLink Technologies - Zenedge Zenedge - ZScaler Accenture + ACE XML Gateway Cisco + aeSecure aeSecure + AireeCDN Airee + Airlock Phion/Ergon + Alert Logic Alert Logic + AliYunDun Alibaba Cloud Computing + Anquanbao Anquanbao + AnYu AnYu Technologies + Approach Approach + AppWall Radware + Armor Defense Armor + ArvanCloud ArvanCloud + ASP.NET Generic Microsoft + ASPA Firewall ASPA Engineering Co. + Astra Czar Securities + AWS Elastic Load Balancer Amazon + AzionCDN AzionCDN + Azure Front Door Microsoft + Barikode Ethic Ninja + Barracuda Barracuda Networks + Bekchy Faydata Technologies Inc. + Beluga CDN Beluga + BIG-IP Local Traffic Manager F5 Networks + BinarySec BinarySec + BitNinja BitNinja + BlockDoS BlockDoS + Bluedon Bluedon IST + BulletProof Security Pro AITpro Security + CacheWall Varnish + CacheFly CDN CacheFly + Comodo cWatch Comodo CyberSecurity + CdnNS Application Gateway CdnNs/WdidcNet + ChinaCache Load Balancer ChinaCache + Chuang Yu Shield Yunaq + Cloudbric Penta Security + Cloudflare Cloudflare Inc. + Cloudfloor Cloudfloor DNS + Cloudfront Amazon + CrawlProtect Jean-Denis Brun + DataPower IBM + DenyALL Rohde & Schwarz CyberSecurity + Distil Distil Networks + DOSarrest DOSarrest Internet Security + DotDefender Applicure Technologies + DynamicWeb Injection Check DynamicWeb + Edgecast Verizon Digital Media + Eisoo Cloud Firewall Eisoo + Expression Engine EllisLab + BIG-IP AppSec Manager F5 Networks + BIG-IP AP Manager F5 Networks + Fastly Fastly CDN + FirePass F5 Networks + FortiWeb Fortinet + GoDaddy Website Protection GoDaddy + Greywizard Grey Wizard + Huawei Cloud Firewall Huawei + HyperGuard Art of Defense + Imunify360 CloudLinux + Incapsula Imperva Inc. + IndusGuard Indusface + Instart DX Instart Logic + ISA Server Microsoft + Janusec Application Gateway Janusec + Jiasule Jiasule + Kona SiteDefender Akamai + KS-WAF KnownSec + KeyCDN KeyCDN + LimeLight CDN LimeLight + LiteSpeed LiteSpeed Technologies + Open-Resty Lua Nginx FLOSS + Oracle Cloud Oracle + Malcare Inactiv + MaxCDN MaxCDN + Mission Control Shield Mission Control + ModSecurity SpiderLabs + NAXSI NBS Systems + Nemesida PentestIt + NevisProxy AdNovum + NetContinuum Barracuda Networks + NetScaler AppFirewall Citrix Systems + Newdefend NewDefend + NexusGuard Firewall NexusGuard + NinjaFirewall NinTechNet + NullDDoS Protection NullDDoS + NSFocus NSFocus Global Inc. + OnMessage Shield BlackBaud + Palo Alto Next Gen Firewall Palo Alto Networks + PerimeterX PerimeterX + PentaWAF Global Network Services + pkSecurity IDS pkSec + PT Application Firewall Positive Technologies + PowerCDN PowerCDN + Profense ArmorLogic + Puhui Puhui + Qiniu Qiniu CDN + Reblaze Reblaze + RSFirewall RSJoomla! + RequestValidationMode Microsoft + Sabre Firewall Sabre + Safe3 Web Firewall Safe3 + Safedog SafeDog + Safeline Chaitin Tech. + SecKing SecKing + eEye SecureIIS BeyondTrust + SecuPress WP Security SecuPress + SecureSphere Imperva Inc. + Secure Entry United Security Providers + SEnginx Neusoft + ServerDefender VP Port80 Software + Shield Security One Dollar Plugin + Shadow Daemon Zecure + SiteGround SiteGround + SiteGuard Sakura Inc. + Sitelock TrueShield + SonicWall Dell + UTM Web Protection Sophos + Squarespace Squarespace + SquidProxy IDS SquidProxy + StackPath StackPath + Sucuri CloudProxy Sucuri Inc. + Tencent Cloud Firewall Tencent Technologies + Teros Citrix Systems + Trafficshield F5 Networks + TransIP Web Firewall TransIP + URLMaster SecurityCheck iFinity/DotNetNuke + URLScan Microsoft + UEWaf UCloud + Varnish OWASP + Viettel Cloudrity + VirusDie VirusDie LLC + Wallarm Wallarm Inc. + WatchGuard WatchGuard Technologies + WebARX WebARX Security Solutions + WebKnight AQTRONIX + WebLand WebLand + RayWAF WebRay Solutions + WebSEAL IBM + WebTotem WebTotem + West263 CDN West263CDN + Wordfence Defiant + WP Cerber Security Cerber Tech + WTS-WAF WTS + 360WangZhanBao 360 Technologies + XLabs Security WAF XLabs + Xuanwudun Xuanwudun + Yundun Yundun + Yunsuo Yunsuo + Yunjiasu Baidu Cloud Computing + YXLink YxLink Technologies + Zenedge Zenedge + ZScaler Accenture + e3Learning Firewall ``` ## How do I use it? @@ -214,24 +226,21 @@ For help you can make use of the `--help` option. The basic usage is to pass an URL as an argument. Example: ``` -$ wafw00f https://example.org +$ wafw00f https://example.org - ______ - / \ - ( W00f! ) - \ ____/ - ,, __ 404 Hack Not Found - |`-.__ / / __ __ - /" _/ /_/ \ \ / / - *===* / \ \_/ / 405 Not Allowed - / )__// \ / - /| / /---` 403 Forbidden - \\/` \ | / _ \ - `\ /_\\_ 502 Bad Gateway / / \ \ 500 Internal Error - `_____``-` /_/ \_\ + ______ + / \ + ( Woof! ) + \ ____/ ) + ,, ) (_ + .-. - _______ ( |__| + ()``; |==|_______) .)|__| + / (' /|\ ( |__| + ( / ) / | \ . |__| + \(_)_)) / | \ |__| - ~ WAFW00F : v2.0.0 ~ - The Web Application Firewall Fingerprinting Toolkit + ~ WAFW00F : v2.1.0 ~ + The Web Application Firewall Fingerprinting Toolkit [*] Checking https://example.org [+] The site https://example.org is behind Edgecast (Verizon Digital Media) WAF. diff -Nru wafw00f-2.0.0/wafw00f/__init__.py wafw00f-2.1.0/wafw00f/__init__.py --- wafw00f-2.0.0/wafw00f/__init__.py 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/wafw00f/__init__.py 2020-01-29 12:24:09.000000000 +0000 @@ -1,4 +1,4 @@ #!/usr/bin/env python -__version__ = '2.0.0' +__version__ = '2.1.0' __license__ = 'BSD 3-Clause' diff -Nru wafw00f-2.0.0/wafw00f/lib/asciiarts.py wafw00f-2.1.0/wafw00f/lib/asciiarts.py --- wafw00f-2.0.0/wafw00f/lib/asciiarts.py 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/wafw00f/lib/asciiarts.py 2020-01-29 12:24:09.000000000 +0000 @@ -36,7 +36,7 @@ '''+Y+'''( / ) '''+G+''' / | \ '''+R+'''. '''+Y+'''|__| '''+Y+r'''\(_)_)) '''+G+'''/ | \ '''+Y+'''|__|'''+E+''' - '''+C+'~ WAFW00F : '+W+'v'+__version__+''' ~ + '''+C+'~ WAFW00F : '+B+'v'+__version__+''' ~'''+W+''' The Web Application Firewall Fingerprinting Toolkit '''+E diff -Nru wafw00f-2.0.0/wafw00f/lib/evillib.py wafw00f-2.1.0/wafw00f/lib/evillib.py --- wafw00f-2.0.0/wafw00f/lib/evillib.py 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/wafw00f/lib/evillib.py 2020-01-29 12:24:09.000000000 +0000 @@ -8,6 +8,8 @@ import sys import time import logging +from copy import copy + import requests import urllib3 try: @@ -56,7 +58,7 @@ return (hostname, port, path, query, ssl) class waftoolsengine: - def __init__(self, target='https://example.com', port=None, debuglevel=0, path='/', proxies=None, + def __init__(self, target='https://example.com', debuglevel=0, path='/', proxies=None, redir=True, head=None): self.target = target self.debuglevel = debuglevel @@ -66,12 +68,10 @@ self.allowredir = redir self.proxies = proxies self.log = logging.getLogger('wafw00f') - if port: - self.target = self.target + ':' + str(port) if head: self.headers = head else: - self.headers = def_headers + self.headers = copy(def_headers) #copy object by value not reference. Fix issue #90 def Request(self, headers=None, path=None, params={}, delay=0, timeout=7): try: diff -Nru wafw00f-2.0.0/wafw00f/main.py wafw00f-2.1.0/wafw00f/main.py --- wafw00f-2.0.0/wafw00f/main.py 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/wafw00f/main.py 2020-01-29 12:24:09.000000000 +0000 @@ -4,25 +4,22 @@ Copyright (C) 2019, WAFW00F Developers. See the LICENSE file for copying permission. ''' - +import csv import io +import json import logging import os import random import re import sys +from collections import defaultdict from optparse import OptionParser - +from wafw00f.lib.asciiarts import * from wafw00f import __version__, __license__ from wafw00f.manager import load_plugins from wafw00f.wafprio import wafdetectionsprio -from wafw00f.lib.asciiarts import * from wafw00f.lib.evillib import urlParser, waftoolsengine, def_headers -currentDir = os.getcwd() -scriptDir = os.path.dirname(sys.argv[0]) or '.' -os.chdir(scriptDir) - class WAFW00F(waftoolsengine): xsstring = '' @@ -31,12 +28,12 @@ rcestring = '/bin/cat /etc/passwd; ping 127.0.0.1; curl google.com' xxestring = ']>&hack;' - def __init__(self, target='www.example.com', port=None, debuglevel=0, path='/', + def __init__(self, target='www.example.com', debuglevel=0, path='/', followredirect=True, extraheaders={}, proxies=None): self.log = logging.getLogger('wafw00f') self.attackres = None - waftoolsengine.__init__(self, target, port, debuglevel, path, proxies, followredirect, extraheaders) + waftoolsengine.__init__(self, target, debuglevel, path, proxies, followredirect, extraheaders) self.knowledge = dict(generic=dict(found=False, reason=''), wafname=list()) def normalRequest(self): @@ -87,7 +84,8 @@ try: # Testing for no user-agent response. Detects almost all WAFs out there. resp1 = self.performCheck(self.normalRequest) - del def_headers['User-Agent'] # Deleting the user-agent key + if 'User-Agent' in self.headers: + del self.headers['User-Agent'] # Deleting the user-agent key from object not dict. resp3 = self.customRequest(headers=def_headers) if resp1.status_code != resp3.status_code: self.log.info('Server returned a different response when request didn\'t contain the User-Agent header.') @@ -245,11 +243,55 @@ level = 0 return level +def buildResultRecord(url, waf): + result = {} + result['url'] = url + if waf: + result['detected'] = True + if waf == 'generic': + result['firewall'] = 'Generic' + result['manufacturer'] = 'Unknown' + else: + result['firewall'] = waf.split('(')[0].strip() + result['manufacturer'] = waf.split('(')[1].replace(')', '').strip() + else: + result['detected'] = False + result['firewall'] = 'None' + result['manufacturer'] = 'None' + return result + +def getTextResults(res=None): + # leaving out some space for future possibilities of newer columns + # newer columns can be added to this tuple below + keys = ('detected') + res = [({key: ba[key] for key in ba if key not in keys}) for ba in res] + rows = [] + for dk in res: + p = [str(x) for _, x in dk.items()] + rows.append(p) + for m in rows: + m[1] = f'{m[1]} ({m[2]})' + m.pop() + defgen = [ + (max([len(str(row[i])) for row in rows]) + 3) + for i in range(len(rows[0])) + ] + rwfmt = "".join(["{:>"+str(dank)+"}" for dank in defgen]) + textresults = [] + for row in rows: + textresults.append(rwfmt.format(*row)) + return textresults + +def disableStdOut(): + sys.stdout = None + +def enableStdOut(): + sys.stdout = sys.__stdout__ + def getheaders(fn): headers = {} - fullfn = os.path.abspath(os.path.join(os.getcwd(), fn)) - if not os.path.exists(fullfn): - logging.getLogger('wafw00f').critical('Headers file "%s" does not exist!' % fullfn) + if not os.path.exists(fn): + logging.getLogger('wafw00f').critical('Headers file "%s" does not exist!' % fn) return with io.open(fn, 'r', encoding='utf-8') as f: for line in f.readlines(): @@ -263,7 +305,6 @@ pass def main(): - print(randomArt()) parser = OptionParser(usage='%prog url1 [url2 [url3 ... ]]\r\nexample: %prog http://www.victim.org/') parser.add_option('-v', '--verbose', action='count', dest='verbose', default=0, help='Enable verbosity, multiple -v options increase verbosity') @@ -272,6 +313,10 @@ parser.add_option('-r', '--noredirect', action='store_false', dest='followredirect', default=True, help='Do not follow redirections given by 3xx responses') parser.add_option('-t', '--test', dest='test', help='Test for one specific WAF') + parser.add_option('-o', '--output', dest='output', help='Write output to csv, json or text file depending on file extension. For stdout, specify - as filename.', + default=None) + parser.add_option('-i', '--input-file', dest='input', help='Read targets from a file. Input format can be csv, json or text. For csv and json, a `url` column name or element is required.', + default=None) parser.add_option('-l', '--list', dest='list', action='store_true', default=False, help='List all WAFs that WAFW00F is able to detect') parser.add_option('-p', '--proxy', dest='proxy', default=None, @@ -283,19 +328,27 @@ options, args = parser.parse_args() logging.basicConfig(level=calclogginglevel(options.verbose)) log = logging.getLogger('wafw00f') + if options.output == '-': + disableStdOut() + print(randomArt()) if options.list: print('[+] Can test for these WAFs:\r\n') attacker = WAFW00F(None) try: m = [i.replace(')', '').split(' (') for i in wafdetectionsprio] - print(R+' WAF Name'+'\t'*3+'Manufacturer\n '+'-'*8+'\t'*3+'-'*12+E+'\n') - for i in m: - tab, n = '\t', 5 - for j in range(-2,23,8): - if len(i[0]) < j: - print(' '+Y+i[0]+E+tab*n+W+i[1]+E) - break - else: n=n-1 + print(R+' WAF Name'+' '*24+'Manufacturer\n '+'-'*8+' '*24+'-'*12+'\n') + max_len = max(len(str(x)) for k in m for x in k) + for inner in m: + first = True + for elem in inner: + if first: + text = Y+" {:<{}} ".format(elem, max_len+2) + first = False + else: + text = W+"{:<{}} ".format(elem, max_len+2) + print(text, E, end="") + print() + sys.exit(0) except Exception: return if options.version: @@ -308,13 +361,42 @@ extraheaders = getheaders(options.headers) if extraheaders is None: parser.error('Please provide a headers file with colon delimited header names and values') - if len(args) == 0: + if len(args) == 0 and not options.input: parser.error('No test target specified.') - targets = args + #check if input file is present + if options.input: + log.debug("Loading file '%s'" % options.input) + try: + if options.input.endswith('.json'): + with open(options.input) as f: + try: + urls = json.loads(f.read()) + except json.decoder.JSONDecodeError: + log.critical("JSON file %s did not contain well-formed JSON", options.input) + sys.exit(1) + log.info("Found: %s urls to check." %(len(urls))) + targets = [ item['url'] for item in urls ] + elif options.input.endswith('.csv'): + columns = defaultdict(list) + with open(options.input) as f: + reader = csv.DictReader(f) + for row in reader: + for (k,v) in row.items(): + columns[k].append(v) + targets = columns['url'] + else: + with open(options.input) as f: + targets = [x for x in f.read().splitlines()] + except FileNotFoundError: + log.error('File %s could not be read. No targets loaded.', options.input) + sys.exit(1) + else: + targets = args + results = [] for target in targets: if not target.startswith('http'): log.info('The url %s should start with http:// or https:// .. fixing (might make this unusable)' % target) - target = 'http://' + target + target = 'https://' + target print('[*] Checking %s' % target) pret = urlParser(target) if pret is None: @@ -328,7 +410,7 @@ "http": options.proxy, "https": options.proxy, } - attacker = WAFW00F(target, port=port, debuglevel=options.verbose, path=path, + attacker = WAFW00F(target, debuglevel=options.verbose, path=path, followredirect=options.followredirect, extraheaders=extraheaders, proxies=proxies) global rq @@ -344,11 +426,13 @@ else: print('[-] WAF %s was not detected on %s' % (options.test, target)) else: - print('WAF %s was not found in our list\r\nUse the --list option to see what is available' % options.test) + print('[-] WAF %s was not found in our list\r\nUse the --list option to see what is available' % options.test) return waf = attacker.identwaf(options.findall) log.info('Identified WAF: %s' % waf) if len(waf) > 0: + for i in waf: + results.append(buildResultRecord(target, i)) print('[+] The site %s%s%s is behind %s%s%s WAF.' % (B, target, E, C, (E+' and/or '+C).join(waf), E)) if (options.findall) or len(waf) == 0: print('[+] Generic Detection results:') @@ -356,9 +440,38 @@ log.info('Generic Detection: %s' % attacker.knowledge['generic']['reason']) print('[*] The site %s seems to be behind a WAF or some sort of security solution' % target) print('[~] Reason: %s' % attacker.knowledge['generic']['reason']) + results.append(buildResultRecord(target, 'generic')) else: print('[-] No WAF detected by the generic detection') + results.append(buildResultRecord(target, None)) print('[~] Number of requests: %s' % attacker.requestnumber) + #print table of results + if len(results) > 0: + log.info("Found: %s matches." % (len(results))) + if options.output: + if options.output == '-': + enableStdOut() + print(os.linesep.join(getTextResults(results))) + elif options.output.endswith('.json'): + log.debug("Exporting data in json format to file: %s" % (options.output)) + with open(options.output, 'w') as outfile: + json.dump(results, outfile, indent=2) + elif options.output.endswith('.csv'): + log.debug("Exporting data in csv format to file: %s" % (options.output)) + with open(options.output, 'w') as outfile: + csvwriter = csv.writer(outfile, delimiter=',', quotechar='"', + quoting=csv.QUOTE_MINIMAL) + count = 0 + for result in results: + if count == 0: + header = result.keys() + csvwriter.writerow(header) + count += 1 + csvwriter.writerow(result.values()) + else: + log.debug("Exporting data in text format to file: %s" % (options.output)) + with open(options.output, 'w') as outfile: + outfile.write(os.linesep.join(getTextResults(results))) if __name__ == '__main__': if sys.hexversion < 0x2060000: diff -Nru wafw00f-2.0.0/wafw00f/plugins/frontdoor.py wafw00f-2.1.0/wafw00f/plugins/frontdoor.py --- wafw00f-2.0.0/wafw00f/plugins/frontdoor.py 1970-01-01 00:00:00.000000000 +0000 +++ wafw00f-2.1.0/wafw00f/plugins/frontdoor.py 2020-01-29 12:24:09.000000000 +0000 @@ -0,0 +1,16 @@ +#!/usr/bin/env python +''' +Copyright (C) 2019, WAFW00F Developers. +See the LICENSE file for copying permission. +''' + +NAME = 'Azure Front Door (Microsoft)' + + +def is_waf(self): + schemes = [ + self.matchHeader(('X-Azure-Ref', '.+?')), + ] + if any(i for i in schemes): + return True + return False \ No newline at end of file diff -Nru wafw00f-2.0.0/wafw00f/plugins/rvmode.py wafw00f-2.1.0/wafw00f/plugins/rvmode.py --- wafw00f-2.0.0/wafw00f/plugins/rvmode.py 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/wafw00f/plugins/rvmode.py 2020-01-29 12:24:09.000000000 +0000 @@ -4,7 +4,7 @@ See the LICENSE file for copying permission. ''' -NAME = 'ASP.NET RequestValidationMode (Microsoft)' +NAME = 'RequestValidationMode (Microsoft)' def is_waf(self): diff -Nru wafw00f-2.0.0/wafw00f/wafprio.py wafw00f-2.1.0/wafw00f/wafprio.py --- wafw00f-2.0.0/wafw00f/wafprio.py 2019-12-10 12:07:18.000000000 +0000 +++ wafw00f-2.1.0/wafw00f/wafprio.py 2020-01-29 12:24:09.000000000 +0000 @@ -25,7 +25,9 @@ 'ASP.NET Generic (Microsoft)', 'ASPA Firewall (ASPA Engineering Co.)', 'Astra (Czar Securities)', + 'AWS Elastic Load Balancer (Amazon)', 'AzionCDN (AzionCDN)', + 'Azure Front Door (Microsoft)', 'Barikode (Ethic Ninja)', 'Barracuda (Barracuda Networks)', 'Bekchy (Faydata Technologies Inc.)', @@ -63,6 +65,7 @@ 'FortiWeb (Fortinet)', 'GoDaddy Website Protection (GoDaddy)', 'Greywizard (Grey Wizard)', + 'Huawei Cloud Firewall (Huawei)', 'HyperGuard (Art of Defense)', 'Imunify360 (CloudLinux)', 'Incapsula (Imperva Inc.)', @@ -104,7 +107,8 @@ 'Qiniu (Qiniu CDN)', 'Reblaze (Reblaze)', 'RSFirewall (RSJoomla!)', - 'ASP.NET RequestValidationMode (Microsoft)', + 'RequestValidationMode (Microsoft)', + 'Sabre Firewall (Sabre)', 'Safe3 Web Firewall (Safe3)', 'Safedog (SafeDog)', 'Safeline (Chaitin Tech.)',