首页 > 技术文章 > WAFW00F waf识别工具 源码学习

Waffle 2021-12-08 20:39 原文

我实习工作的第一个任务根据已有的java waf识别工具 实现了一个python的waf识别工具
代码结构非常乱 仅仅达到了能用的水平。
顶头svp推荐这个项目当时我已经写好了开始用了自己的
稍微看了一个这个项目其实之前我就用过指纹库比较老了可能都需要自己来收集
我自己实现的识别工具都是 正则 该工具使用了py程序作为动态加载的插件库
从公司返校一直打算 研究一下这个源码 一直咯咯咯到现在

Github:https://github.com/EnableSecurity/wafw00f

wafw00f是个通过http返回报文来判断waf的识别工具,他发送一个普通的HTTP 请求并分析响应如果不成功,它会发送一些(可能是恶意的)HTTP 请求并使用简单的逻辑来推断它是哪个 WAF,如果这也不成功,它会分析先前返回的响应,并使用另一种简单的算法来猜测 WAF 或安全解决方案是否正在积极响应我们的攻击。

依赖库

1.https://github.com/psf/requests

  • 最流行的http请求库不用说了

2.https://github.com/mitsuhiko/pluginbase

WAFW00F

在实习工作里我也实现了一个类似的工具,主要通过正则来识别 。也碰到了一些问题比如多条正则每次匹配一条所需要的时间特别长我通过 将所有正则进行联用初筛如果发现命中了某条规则再用折半查找来匹配到具体的规则,还发现了一种通过cname来识别云防御的方案不需要攻击行为,甚至不需要进行http请求只需要dns 查询即可。
关于waf00f我们主要关注

  • 动态加载插件
  • 判断waf存在
  • 插件(识别规则)

目录结构

├── __init__.py
├── bin
│   └── wafw00f
├── lib
│   ├── __init__.py
│   ├── asciiarts.py  # banner logo等
│   └── evillib.py      # http请求构造发起等
├── main.py  #主程序
├── manager.py #加载插件
├── plugins #规则库插件目录
└── wafprio.py #优先级检查列表

静态配置

    # payload
    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>'
    
    # headers
    def_headers = {'Accept'         : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
                   'Accept-Encoding': 'gzip, deflate',
                   'Accept-Language': 'en-US,en;q=0.9',
                   'DNT'            : '1',  # Do Not Track request header 要求服务器程序不要跟踪记录用户信息
                   'User-Agent'     : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3770.100 Safari/537.36',
                   'Upgrade-Insecure-Requests': '1' #
            }

插件规则

也是通过正则进行匹配 通过any()或者all()进行规则匹配并命中
这里self.matchCookie self.matchHeader 默认是不进行攻击

#!/usr/bin/env python
'''
Copyright (C) 2020, WAFW00F Developers.
See the LICENSE file for copying permission.
'''

NAME = 'DenyALL (Rohde & Schwarz CyberSecurity)'


def is_waf(self):
    schemes = [
        self.matchStatus(200),
        self.matchReason('Condition Intercepted')
        self.matchHeader(('cf-ray', r'.+?')),
        self.matchCookie(r'^crawlprotecttag='),
        self.matchContent(r'<title>crawlprotect'),
    ]
    if all(i for i in schemes):
        return True
    return False

插件的加载使用对面向对象的运用都特别厉害

聊一聊有趣的地方吧

这款工具一个特别有趣的点是在于对未识别的waf判定

对于正则进行匹配识别指纹以及攻击对拦截页面识别都特别常见
而对不在规则库中的waf识别成为我工作的一大难题
这里
使用了5种方法对未收录指纹的waf的存在进行判断

依次是

  1. 使用无User-agent请求对目标进行请求
  2. 使用xss攻击触发waf
  3. 使用lfi攻击触发waf
  4. 使用sql注入触发waf
  5. 对比正常请求和攻击请求响应中的server 值
    还有一个异常捕获 当任何一次请求出现错误 进行判定

在前4条中都使用了响应吗进行初步判断,而不是使用规则无脑进行匹配 这样可以省去一些时间
在第一条方法中的注释写上了 能检测几乎所有的waf很神奇我居然从来都没想到过
234都比较常见
第五条 也挺有意思 通过servername的值对比判断 这样的话是不是可以使用HADE请求来节省一部分时间

思考

在这款工具上居然丝毫没用到多线程异步等高性能 是没有对应场景吗
我认为可以通过 异步对插件库中的规则进行匹配 而不是使用优先级 甚至可是使用
如果对于我那种不管三七二十一直接打一个payload的方案甚至可以使用 functools中的cache装饰器进行加速毕竟相同waf拦截的页面都是相同的当然这个也是针对场景的 对于我需要的多站点可能存在 相同品牌的waf 比较合适
我一直在想办法 优化规则的匹配速度 ,直到被老大一句话点醒 现阶段最慢的不是硬盘io 而是网络io ,后来我使用了httpx加上异步进行处理结果速度快了一个量级。 感觉之前浪费了好多时间 有时候由于技术实力不够浪费的时间比摸鱼还要可怕。

由于我实在太菜,读这款工具花了我大概一周多的时间。然而还是囫囵吞枣 还是代码写的少了。

推荐阅读