Пример #1
0
class WafW00F(waftoolsengine):

    AdminFolder = '/Admin_Files/'
    xssstring = '<script>alert(1)</script>'
    dirtravstring = '../../../../etc/passwd'
    cleanhtmlstring = '<invalid>hello'

    def __init__(self,
                 target='www.microsoft.com',
                 port=80,
                 ssl=False,
                 debuglevel=0,
                 path='/',
                 followredirect=True,
                 extraheaders={},
                 proxy=False):
        """
        target: the hostname or ip of the target server
        port: defaults to 80
        ssl: defaults to false
        """
        self.log = logging.getLogger('wafw00f')
        waftoolsengine.__init__(self, target, port, ssl, debuglevel, path,
                                followredirect, extraheaders, proxy)
        self.knowledge = dict(generic=dict(found=False, reason=''),
                              wafname=list())

    def normalrequest(self, usecache=True, cacheresponse=True, headers=None):
        return self.request(usecache=usecache,
                            cacheresponse=cacheresponse,
                            headers=headers)

    def normalnonexistentfile(self, usecache=True, cacheresponse=True):
        path = self.path + str(random.randrange(1000, 9999)) + '.html'
        return self.request(path=path,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def unknownmethod(self, usecache=True, cacheresponse=True):
        return self.request(method='OHYEA',
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def directorytraversal(self, usecache=True, cacheresponse=True):
        return self.request(path=self.path + self.dirtravstring,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def invalidhost(self, usecache=True, cacheresponse=True):
        randomnumber = random.randrange(100000, 999999)
        return self.request(headers={'Host': str(randomnumber)})

    def cleanhtmlencoded(self, usecache=True, cacheresponse=True):
        string = self.path + quote(self.cleanhtmlstring) + '.html'
        return self.request(path=string,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def cleanhtml(self, usecache=True, cacheresponse=True):
        string = self.path + '?htmli=' + self.cleanhtmlstring
        return self.request(path=string,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def xssstandard(self, usecache=True, cacheresponse=True):
        xssstringa = self.path + '?xss=' + self.xssstring
        return self.request(path=xssstringa,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def protectedfolder(self, usecache=True, cacheresponse=True):
        pfstring = self.path + self.AdminFolder
        return self.request(path=pfstring,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def xssstandardencoded(self, usecache=True, cacheresponse=True):
        xssstringb = self.path + quote(self.xssstring) + '.html'
        return self.request(path=xssstringb,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    attacks = [
        xssstandard, directorytraversal, protectedfolder, xssstandardencoded
    ]

    def genericdetect(self, usecache=True, cacheresponse=True):
        knownflops = [
            ('Microsoft-IIS/7.0', 'Microsoft-HTTPAPI/2.0'),
        ]
        reason = ''
        reasons = [
            'Blocking is being done at connection/packet level.',
            'The server header is different when an attack is detected.',
            'The server returned a different response code when a string trigged the blacklist.',
            'It closed the connection for a normal request.',
            'The connection header was scrambled.'
        ]
        # test if response for a path containing html tags with known evil strings
        # gives a different response from another containing invalid html tags
        try:
            cleanresponse, _tmp = self._perform_and_check(self.cleanhtml)
            xssresponse, _tmp = self._perform_and_check(self.xssstandard)
            if xssresponse.status != cleanresponse.status:
                self.log.info(
                    'Server returned a different response when a script tag was tried'
                )
                reason = reasons[2]
                reason += '\r\n'
                reason += 'Normal response code is "%s",' % cleanresponse.status
                reason += ' while the response code to an attack is "%s"' % xssresponse.status
                self.knowledge['generic']['reason'] = reason
                self.knowledge['generic']['found'] = True
                return True
            cleanresponse, _tmp = self._perform_and_check(
                self.cleanhtmlencoded)
            xssresponse, _tmp = self._perform_and_check(
                self.xssstandardencoded)
            if xssresponse.status != cleanresponse.status:
                self.log.info(
                    'Server returned a different response when a script tag was tried'
                )
                reason = reasons[2]
                reason += '\r\n'
                reason += 'Normal response code is "%s",' % cleanresponse.status
                reason += ' while the response code to an attack is "%s"' % xssresponse.status
                self.knowledge['generic']['reason'] = reason
                self.knowledge['generic']['found'] = True
                return True
            response, _ = self._perform_and_check(self.normalrequest)
            normalserver = response.getheader('Server')
            for attack in self.attacks:
                response, _ = self._perform_and_check(lambda: attack(self))
                attackresponse_server = response.getheader('Server')
                if attackresponse_server:
                    if attackresponse_server != normalserver:
                        if (normalserver, attackresponse_server) in knownflops:
                            return False
                        self.log.info(
                            'Server header changed, WAF possibly detected')
                        self.log.debug('attack response: %s' %
                                       attackresponse_server)
                        self.log.debug('normal response: %s' % normalserver)
                        reason = reasons[1]
                        reason += '\r\nThe server header for a normal response is "%s",' % normalserver
                        reason += ' while the server header a response to an attack is "%s",' % attackresponse_server
                        self.knowledge['generic']['reason'] = reason
                        self.knowledge['generic']['found'] = True
                        return True
            for attack in wafdetectionsprio:
                if self.wafdetections[attack](self) is None:
                    self.knowledge['generic']['reason'] = reasons[0]
                    self.knowledge['generic']['found'] = True
                    return True
            for attack in self.attacks:
                response, _ = self._perform_and_check(lambda: attack(self))
                for h, _ in response.getheaders():
                    if scrambledheader(h):
                        self.knowledge['generic']['reason'] = reasons[4]
                        self.knowledge['generic']['found'] = True
                        return True
        except RequestBlocked:
            self.knowledge['generic']['reason'] = reasons[0]
            self.knowledge['generic']['found'] = True
            return True

        return False

    def _perform_and_check(self, request_method):
        r = request_method()
        if r is None:
            raise RequestBlocked()

        return r

    def matchheader(self, headermatch, attack=False, ignorecase=True):
        import re

        detected = False
        header, match = headermatch
        if attack:
            requests = self.attacks
        else:
            requests = [self.normalrequest]
        for request in requests:
            r = request(self)
            if r is None:
                return
            response, _ = r
            headerval = response.getheader(header)
            if headerval:
                # set-cookie can have multiple headers, python gives it to us
                # concatinated with a comma
                if header == 'set-cookie':
                    headervals = headerval.split(', ')
                else:
                    headervals = [headerval]
                for headerval in headervals:
                    if ignorecase:
                        if re.search(match, headerval, re.IGNORECASE):
                            detected = True
                            break
                    else:
                        if re.search(match, headerval):
                            detected = True
                            break
                if detected:
                    break
        return detected

    def matchcookie(self, match):
        """
        a convenience function which calls matchheader
        """
        return self.matchheader(('set-cookie', match))

    wafdetections = dict()

    plugin_dict = load_plugins()
    result_dict = {}
    for plugin_module in plugin_dict.values():
        wafdetections[plugin_module.NAME] = plugin_module.is_waf

    def identwaf(self, findall=False):
        detected = list()

        # Check for prioritized ones first, then check those added externally
        checklist = wafdetectionsprio
        checklist += list(set(self.wafdetections.keys()) - set(checklist))

        for wafvendor in checklist:
            self.log.info('Checking for %s' % wafvendor)
            if self.wafdetections[wafvendor](self):
                detected.append(wafvendor)
                if not findall:
                    break
        self.knowledge['wafname'] = detected
        return detected
Пример #2
0
class WAFW00F(waftoolsengine):
    xsstring = '<script>alert("XSS");</script>'
    sqlistring = "UNION SELECT ALL FROM information_schema AND ' or SLEEP(5) or '"
    lfistring = '../../../../etc/passwd'
    rcestring = '/bin/cat /etc/passwd; ping 127.0.0.1; curl google.com'
    xxestring = '<!ENTITY xxe SYSTEM "file:///etc/shadow">]><pwn>&hack;</pwn>'

    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, debuglevel, path, proxies, followredirect, extraheaders)
        self.knowledge = dict(generic=dict(found=False, reason=''), wafname=list())

    def normalRequest(self):
        return self.Request()

    def customRequest(self, headers=None):
        return self.Request(headers=headers)

    def nonExistent(self):
        return self.Request(path=self.path + str(random.randrange(100, 999)) + '.html')

    def xssAttack(self):
        return self.Request(path=self.path, params={'s': self.xsstring})

    def xxeAttack(self):
        return self.Request(path=self.path, params={'s': self.xxestring})

    def lfiAttack(self):
        return self.Request(path=self.path + self.lfistring)

    def centralAttack(self):
        return self.Request(path=self.path, params={'a': self.xsstring, 'b': self.sqlistring, 'c': self.lfistring})

    def sqliAttack(self):
        return self.Request(path=self.path, params={'s': self.sqlistring})

    def oscAttack(self):
        return self.Request(path=self.path, params={'s': self.rcestring})

    def performCheck(self, request_method):
        r = request_method()
        if r is None:
            raise RequestBlocked()
        return r

    # Most common attacks used to detect WAFs
    attcom = [xssAttack, sqliAttack, lfiAttack]
    attacks = [xssAttack, xxeAttack, lfiAttack, sqliAttack, oscAttack]

    def genericdetect(self):
        reason = ''
        reasons = ['Blocking is being done at connection/packet level.',
                   'The server header is different when an attack is detected.',
                   'The server returns a different response code when an attack string is used.',
                   'It closed the connection for a normal request.',
                   'The response was different when the request wasn\'t made from a browser.'
                   ]
        try:
            # Testing for no user-agent response. Detects almost all WAFs out there.
            resp1 = self.performCheck(self.normalRequest)
            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.')
                reason = reasons[4]
                reason += '\r\n'
                reason += 'Normal response code is "%s",' % resp1.status_code
                reason += ' while the response code to a modified request is "%s"' % resp3.status_code
                self.knowledge['generic']['reason'] = reason
                self.knowledge['generic']['found'] = True
                return True

            # Testing the status code upon sending a xss attack
            resp2 = self.performCheck(self.xssAttack)
            if resp1.status_code != resp2.status_code:
                self.log.info('Server returned a different response when a XSS attack vector was tried.')
                reason = reasons[2]
                reason += '\r\n'
                reason += 'Normal response code is "%s",' % resp1.status_code
                reason += ' while the response code to cross-site scripting attack is "%s"' % resp2.status_code
                self.knowledge['generic']['reason'] = reason
                self.knowledge['generic']['found'] = True
                return True

            # Testing the status code upon sending a lfi attack
            resp2 = self.performCheck(self.lfiAttack)
            if resp1.status_code != resp2.status_code:
                self.log.info('Server returned a different response when a directory traversal was attempted.')
                reason = reasons[2]
                reason += '\r\n'
                reason += 'Normal response code is "%s",' % resp1.status_code
                reason += ' while the response code to a file inclusion attack is "%s"' % resp2.status_code
                self.knowledge['generic']['reason'] = reason
                self.knowledge['generic']['found'] = True
                return True

            # Testing the status code upon sending a sqli attack
            resp2 = self.performCheck(self.sqliAttack)
            if resp1.status_code != resp2.status_code:
                self.log.info('Server returned a different response when a SQLi was attempted.')
                reason = reasons[2]
                reason += '\r\n'
                reason += 'Normal response code is "%s",' % resp1.status_code
                reason += ' while the response code to a SQL injection attack is "%s"' % resp2.status_code
                self.knowledge['generic']['reason'] = reason
                self.knowledge['generic']['found'] = True
                return True

            # Checking for the Server header after sending malicious requests
            response = self.attackres
            normalserver = resp1.headers.get('Server')
            attackresponse_server = response.headers.get('Server')
            if attackresponse_server:
                if attackresponse_server != normalserver:
                    self.log.info('Server header changed, WAF possibly detected')
                    self.log.debug('Attack response: %s' % attackresponse_server)
                    self.log.debug('Normal response: %s' % normalserver)
                    reason = reasons[1]
                    reason += '\r\nThe server header for a normal response is "%s",' % normalserver
                    reason += ' while the server header a response to an attack is "%s",' % attackresponse_server
                    self.knowledge['generic']['reason'] = reason
                    self.knowledge['generic']['found'] = True
                    return True

        # If at all request doesn't go, press F
        except RequestBlocked:
            self.knowledge['generic']['reason'] = reasons[0]
            self.knowledge['generic']['found'] = True
            return True
        return False

    def matchHeader(self, headermatch, attack=False):
        if attack:
            r = self.attackres
        else:
            r = rq
        if r is None:
            return
        header, match = headermatch
        headerval = r.headers.get(header)
        if headerval:
            # set-cookie can have multiple headers, python gives it to us
            # concatinated with a comma
            if header == 'Set-Cookie':
                headervals = headerval.split(', ')
            else:
                headervals = [headerval]
            for headerval in headervals:
                if re.search(match, headerval, re.I):
                    return True
        return False

    def matchStatus(self, statuscode, attack=True):
        if attack:
            r = self.attackres
        else:
            r = rq
        if r is None:
            return
        if r.status_code == statuscode:
            return True
        return False

    def matchCookie(self, match, attack=False):
        return self.matchHeader(('Set-Cookie', match), attack=attack)

    def matchReason(self, reasoncode, attack=True):
        if attack:
            r = self.attackres
        else:
            r = rq
        if r is None:
            return
        # We may need to match multiline context in response body
        if str(r.reason) == reasoncode:
            return True
        return False

    def matchContent(self, regex, attack=True):
        if attack:
            r = self.attackres
        else:
            r = rq
        if r is None:
            return
        # We may need to match multiline context in response body
        if re.search(regex, r.text, re.I):
            return True
        return False

    wafdetections = dict()

    plugin_dict = load_plugins()
    result_dict = {}
    for plugin_module in plugin_dict.values():
        wafdetections[plugin_module.NAME] = plugin_module.is_waf
    # Check for prioritized ones first, then check those added externally
    checklist = wafdetectionsprio
    checklist += list(set(wafdetections.keys()) - set(checklist))

    def identwaf(self, findall=False):
        detected = list()
        try:
            self.attackres = self.performCheck(self.centralAttack)
        except RequestBlocked:
            return detected
        for wafvendor in self.checklist:
            self.log.info('Checking for %s' % wafvendor)
            if self.wafdetections[wafvendor](self):
                detected.append(wafvendor)
                if not findall:
                    break
        self.knowledge['wafname'] = detected
        return detected
Пример #3
0
class WafW00F(waftoolsengine):
    """
    WAF detection tool
    """

    AdminFolder = '/Admin_Files/'
    xssstring = '<script>alert(1)</script>'
    dirtravstring = '../../../../etc/passwd'
    cleanhtmlstring = '<invalid>hello'
    isaservermatch = [
        'Forbidden ( The server denied the specified Uniform Resource Locator (URL). Contact the server administrator.  )',
        'Forbidden ( The ISA Server denied the specified Uniform Resource Locator (URL)'
    ]

    def __init__(self,
                 target='www.microsoft.com',
                 port=80,
                 ssl=False,
                 debuglevel=0,
                 path='/',
                 followredirect=True,
                 extraheaders={},
                 proxy=False):
        """
        target: the hostname or ip of the target server
        port: defaults to 80
        ssl: defaults to false
        """
        self.log = logging.getLogger('wafw00f')
        waftoolsengine.__init__(self, target, port, ssl, debuglevel, path,
                                followredirect, extraheaders, proxy)
        self.knowledge = dict(generic=dict(found=False, reason=''),
                              wafname=list())

    def normalrequest(self, usecache=True, cacheresponse=True, headers=None):
        return self.request(usecache=usecache,
                            cacheresponse=cacheresponse,
                            headers=headers)

    def normalnonexistentfile(self, usecache=True, cacheresponse=True):
        path = self.path + str(random.randrange(1000, 9999)) + '.html'
        return self.request(path=path,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def unknownmethod(self, usecache=True, cacheresponse=True):
        return self.request(method='OHYEA',
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def directorytraversal(self, usecache=True, cacheresponse=True):
        return self.request(path=self.path + self.dirtravstring,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def invalidhost(self, usecache=True, cacheresponse=True):
        randomnumber = random.randrange(100000, 999999)
        return self.request(headers={'Host': str(randomnumber)})

    def cleanhtmlencoded(self, usecache=True, cacheresponse=True):
        string = self.path + quote(self.cleanhtmlstring) + '.html'
        return self.request(path=string,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def cleanhtml(self, usecache=True, cacheresponse=True):
        string = self.path + self.cleanhtmlstring + '.html'
        return self.request(path=string,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def xssstandard(self, usecache=True, cacheresponse=True):
        xssstringa = self.path + self.xssstring + '.html'
        return self.request(path=xssstringa,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def protectedfolder(self, usecache=True, cacheresponse=True):
        pfstring = self.path + self.AdminFolder
        return self.request(path=pfstring,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def xssstandardencoded(self, usecache=True, cacheresponse=True):
        xssstringa = self.path + quote(self.xssstring) + '.html'
        return self.request(path=xssstringa,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    def cmddotexe(self, usecache=True, cacheresponse=True):
        # thanks j0e
        string = self.path + 'cmd.exe'
        return self.request(path=string,
                            usecache=usecache,
                            cacheresponse=cacheresponse)

    attacks = [
        cmddotexe, directorytraversal, xssstandard, protectedfolder,
        xssstandardencoded
    ]

    def genericdetect(self, usecache=True, cacheresponse=True):
        knownflops = [
            ('Microsoft-IIS/7.0', 'Microsoft-HTTPAPI/2.0'),
        ]
        reason = ''
        reasons = [
            'Blocking is being done at connection/packet level.',
            'The server header is different when an attack is detected.',
            'The server returned a different response code when a string trigged the blacklist.',
            'It closed the connection for a normal request.',
            'The connection header was scrambled.'
        ]
        # test if response for a path containing html tags with known evil strings
        # gives a different response from another containing invalid html tags
        r = self.cleanhtml()
        if r is None:
            self.knowledge['generic']['reason'] = reasons[0]
            self.knowledge['generic']['found'] = True
            return True
        cleanresponse, _tmp = r
        r = self.xssstandard()
        if r is None:
            self.knowledge['generic']['reason'] = reasons[0]
            self.knowledge['generic']['found'] = True
            return True
        xssresponse, _tmp = r
        if xssresponse.status != cleanresponse.status:
            self.log.info(
                'Server returned a different response when a script tag was tried'
            )
            reason = reasons[2]
            reason += '\r\n'
            reason += 'Normal response code is "%s",' % cleanresponse.status
            reason += ' while the response code to an attack is "%s"' % xssresponse.status
            self.knowledge['generic']['reason'] = reason
            self.knowledge['generic']['found'] = True
            return True
        r = self.cleanhtmlencoded()
        cleanresponse, _tmp = r
        r = self.xssstandardencoded()
        if r is None:
            self.knowledge['generic']['reason'] = reasons[0]
            self.knowledge['generic']['found'] = True
            return True
        xssresponse, _tmp = r
        if xssresponse.status != cleanresponse.status:
            self.log.info(
                'Server returned a different response when a script tag was tried'
            )
            reason = reasons[2]
            reason += '\r\n'
            reason += 'Normal response code is "%s",' % cleanresponse.status
            reason += ' while the response code to an attack is "%s"' % xssresponse.status
            self.knowledge['generic']['reason'] = reason
            self.knowledge['generic']['found'] = True
            return True
        response, responsebody = self.normalrequest()
        normalserver = response.getheader('Server')
        for attack in self.attacks:
            r = attack(self)
            if r is None:
                self.knowledge['generic']['reason'] = reasons[0]
                self.knowledge['generic']['found'] = True
                return True
            response, responsebody = r
            attackresponse_server = response.getheader('Server')
            if attackresponse_server:
                if attackresponse_server != normalserver:
                    if (normalserver, attackresponse_server) in knownflops:
                        return False
                    self.log.info(
                        'Server header changed, WAF possibly detected')
                    self.log.debug('attack response: %s' %
                                   attackresponse_server)
                    self.log.debug('normal response: %s' % normalserver)
                    reason = reasons[1]
                    reason += '\r\nThe server header for a normal response is "%s",' % normalserver
                    reason += ' while the server header a response to an attack is "%s.",' % attackresponse_server
                    self.knowledge['generic']['reason'] = reason
                    self.knowledge['generic']['found'] = True
                    return True
        for attack in self.wafdetectionsprio:
            if self.wafdetections[attack](self) is None:
                self.knowledge['generic']['reason'] = reasons[0]
                self.knowledge['generic']['found'] = True
                return True
        for attack in self.attacks:
            r = attack(self)
            if r is None:
                self.knowledge['generic']['reason'] = reasons[0]
                self.knowledge['generic']['found'] = True
                return True
            response, responsebody = r
            for h, v in response.getheaders():
                if scrambledheader(h):
                    self.knowledge['generic']['reason'] = reasons[4]
                    self.knowledge['generic']['found'] = True
                    return True
        return False

    def matchheader(self, headermatch, attack=False, ignorecase=True):
        import re

        detected = False
        header, match = headermatch
        if attack:
            requests = self.attacks
        else:
            requests = [self.normalrequest]
        for request in requests:
            r = request(self)
            if r is None:
                return
            response, responsebody = r
            headerval = response.getheader(header)
            if headerval:
                # set-cookie can have multiple headers, python gives it to us
                # concatinated with a comma
                if header == 'set-cookie':
                    headervals = headerval.split(', ')
                else:
                    headervals = [headerval]
                for headerval in headervals:
                    if ignorecase:
                        if re.match(match, headerval, re.IGNORECASE):
                            detected = True
                            break
                    else:
                        if re.match(match, headerval):
                            detected = True
                            break
                if detected:
                    break
        return detected

    def matchcookie(self, match):
        """
        a convenience function which calls matchheader
        """
        return self.matchheader(('set-cookie', match))

    def isbeeware(self):
        # disabled cause it was giving way too many false positives
        # credit goes to Sebastien Gioria
        detected = False
        r = self.xssstandard()
        if r is None:
            return
        response, responsebody = r
        if (response.status != 200) or (response.reason == 'Forbidden'):
            r = self.directorytraversal()
            if r is None:
                return
            response, responsebody = r
            if response.status == 403:
                if response.reason == 'Forbidden':
                    detected = True
        return detected

    def ismodsecuritypositive(self):
        detected = False
        self.normalrequest(usecache=False, cacheresponse=False)
        randomfn = self.path + str(random.randrange(1000, 9999)) + '.html'
        r = self.request(path=randomfn)
        if r is None:
            return
        response, responsebody = r
        if response.status != 302:
            return False
        randomfnnull = randomfn + '%00'
        r = self.request(path=randomfnnull)
        if r is None:
            return
        response, responsebody = r
        if response.status == 404:
            detected = True
        return detected

    wafdetections = dict()

    # easy ones
    # lil bit more complex
    #wafdetections['BeeWare'] = isbeeware
    #wafdetections['ModSecurity (positive model)'] = ismodsecuritypositive removed for now
    wafdetectionsprio = [
        'Profense',
        'NetContinuum',
        'Incapsula WAF',
        'CloudFlare',
        'NSFocus',
        'Safedog',
        'Mission Control Application Shield',
        'USP Secure Entry Server',
        'Cisco ACE XML Gateway',
        'Barracuda Application Firewall',
        'Art of Defence HyperGuard',
        'BinarySec',
        'Teros WAF',
        'F5 BIG-IP LTM',
        'F5 BIG-IP APM',
        'F5 BIG-IP ASM',
        'F5 FirePass',
        'F5 Trafficshield',
        'InfoGuard Airlock',
        'Citrix NetScaler',
        'Trustwave ModSecurity',
        'IBM Web Application Security',
        'IBM DataPower',
        'DenyALL WAF',
        'Applicure dotDefender',
        'Juniper WebApp Secure',  # removed for now 'ModSecurity (positive model)',
        'Microsoft URLScan',
        'Aqtronix WebKnight',
        'eEye Digital Security SecureIIS',
        'Imperva SecureSphere',
        'Microsoft ISA Server'
    ]

    plugin_dict = load_plugins()
    result_dict = {}
    for plugin_module in plugin_dict.values():
        wafdetections[plugin_module.NAME] = plugin_module.is_waf

    def identwaf(self, findall=False):
        detected = list()

        # Check for prioritized ones first, then check those added externally
        checklist = self.wafdetectionsprio
        checklist = checklist + list(
            set(self.wafdetections.keys()) - set(checklist))

        for wafvendor in checklist:
            self.log.info('Checking for %s' % wafvendor)
            if self.wafdetections[wafvendor](self):
                detected.append(wafvendor)
                if not findall:
                    break
        self.knowledge['wafname'] = detected
        return detected