3

聊聊 Wafw00f 源码及流量特征

 1 year ago
source link: https://www.51cto.com/article/740998.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

聊聊 Wafw00f 源码及流量特征

作者:Deutsh 2022-11-30 09:51:02
所谓源码解析并不会完整分析其源码中的所有功能,比如 日志、输出、展示 等功能不在我们分析的范围内,而其对 WAF 的检测逻辑、所发流量的特征、WAF 识别的指纹等将是重点要分析的地方。

wafw00f介绍

这不是本次的重点,相关介绍及使用方法相信大家已经了解,所以此处就直接引用其开发者对该工具的介绍。

1668779762_63778ef2c9b5f811b18aa.png!small?1668779761475

To do its magic, WAFW00F does the following:

  • Sends a normal HTTP request and analyses the response; this identifies a number of WAF solutions.通过发送正常的​HTTP​请求并且分析其返回包,判断其是否使用 WAF ,若使用确认WAF类型
  • If that is not successful, it sends a number of (potentially malicious) HTTP requests and uses simple logic to deduce which WAF it is.若是无法通过正常的​HTTP​请求结果分析出是否使用WAF以及其类型,则构造恶意的请求通过简单的逻辑再次进行判断
  • If that is also not successful, it analyses the responses previously returned and uses another simple algorithm to guess if a WAF or security solution is actively responding to our attacks.如果这也不成功,它会分析之前返回的响应,并使用另一种简单的算法来猜测​WAF或安全解决方案是否正在积极响应我们的攻击

使用场景/方法

这不是本次的重点,想要具体了解其用法去其github主页即可

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

本工具的作用上面已经很详细的描述出来了,概括一下很简单:探测目标是否存在WAF,也可以说wafw00f是一个Web应用防火墙(WAF)指纹识别的工具。

使用方法不难,此处不做介绍,若想进一步了解见:WEB 防火墙探测工具 -- wafw00f 使用教程 - General 的个人博客

wafw00f 源码解析

所谓源码解析并不会完整分析其源码中的所有功能,比如 日志、输出、展示 等功能不在我们分析的范围内,而其对 WAF 的检测逻辑、所发流量的特征、WAF 识别的指纹等将是重点要分析的地方。

  • 解析源码含义,分析特征

源码文件结构

为了方便大家之后去看源码,此处简单描述一下源码的组成,其中没有描述的说明其用不大,大家自己去看就知道了,其中标注important是本工具的主要功能文件,后续将重点说明。

1668779769_63778ef9467c1c452a6b5.png!small?1668779767856

asciiarts.py

evillib.py用于向目标建立连接发起请求( important )

  • plugins​用于判断各个WAF的指纹 ( important )

aliyundun.py阿里云盾的特征值匹配文件

huaweicloud.py****华为云的特征值匹配文件

baidu.py百度云加速的特征匹配文件

还有很多特征文件大家自己去看就好

  • __init__.py
  • main.py该工具主要的检测、判断功能的类与函数都在该文件中实现( important )
  • manager.py​加载plugins​中的WAF​指纹判断文件识别目标WAF类型
  • wafprio.py

上述非important的文件起到的作用多是一些起到 输出选项、连接 等功能的文件/函数,所以不做特殊介绍

请求的流程并不复杂,和最开始介绍处的流程如出一辙:

  • 发送正常HTTP​请求,并判断是否存在WAF若存在根据指纹判断其类型
  • 若正常HTTP​检测不出WAF​,则附加恶意的请求尝试出发WAF并分析其类型

最后所谓的根据算法猜测,流量特征不明显,不在此次分析的范围内,实际用处也不大。

请求运行流程( important)

以第一次的正常HTTP请求探测为例(其余的都一致)。

1668779774_63778efe6b5b2740e1822.png!small?1668779773039

由于对 Python 并不是太了解,所以作用域的表示采用了C++中的::(若是不对请及时指出会做更改)。

main.py分析

完整的源码就不放在这占地方了,大家随时可到其github主页获取,此处直接分析其重点部分

由上述流程可以看出,所有的请求均是从class WAFW00F中发起,所以该类就是我们分析的重中之重!

请求的具体实现(比如请求中携带了哪些内容)将在分析evillib.py文件是分析,此处主要分析何时要发出何种请求。

从main()函数出发看其逻辑:(解析参数等功能将直接略过)

没有指定其余参数

  • 对输入的URL​做相关处理后放到target​中传入WAFW00F进行处理
attacker = WAFW00F(target, debuglevel=options.verbose, path=path,followredirect=options.followredirect, extraheaders=extraheaders,proxies=proxies)

# 若请求没有结果则说明目标网站或本地网络有问题
if attacker.rq is None:
     log.error('Site %s appears to be down' % hostname)
     continue
  • 由于第一次做的是常规探测,若此处就匹配到了WAF的指纹则输出结束即可,具体的输出等逻辑不是重点,略过;
  • 若无法分析出其是否存在WAF​或匹配不出WAF​则通过identwaf()函数进步拼凑恶意参数进行探测;
waf = attacker.identwaf(options.findall)
log.info('Identified WAF: %s' % waf)
  • 进入identwaf()​函数后,便会尝试匹配各个WAF的特征;
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

这就是基本的流程。

解析来如果还没有确定出WAF便会进入其自己提供的一个算法,但这并不是我们对流量特征分析所要关注的地方,所以就不探讨了。

下面到了激动人心的时刻,WAFW00F类中到底是如何实现的呢?

class WAFW00F

一上来就中了大奖:

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>'

WAFW00F这个工具所要构造拼接的恶意代码在一开始就全部列出了,而且在之后的使用中绝无变化,要构造恶意的请求就是从上述5个字符串中选择1个或多个直接使用。

可以看到改用据用于判断是否存在WAF的语句就以下五类:

  • XSS类                     <script>alert("XSS");</script>
  • SQL注入类              UNION SELECT ALL FROM information_schema AND ' or SLEEP(5) or '
  • 遍历类                    ../../../../etc/passwd
  • 命令执行/拼接类    /bin/cat /etc/passwd; ping 127.0.0.1; curl google.com
  • XXE类                     <!ENTITY xxe SYSTEM "file:///etc/shadow">]><pwn>&hack;</pwn>

那么有了这些语句,WAFW00F又该如何拼接呢?

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})

具体逻辑并不难理解,拿出几种几个来说一下。

1:def xssAttack(self)

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

例如给一个简单的例子:我们传给wafw00f的URL为:http://127.0.0.1:9000则经过该参数拼接后的请求就为:

http://127.0.0.1:9000/?s=<script>alert("XSS");</script>(URL编码前 )。

2:def centralAttack(self):

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

例如给一个简单的例子:我们传给wafw00f的URL为:http://127.0.0.1:9000则经过该参数拼接后的请求就为:

http://127.0.0.1:9000/?s=<script>alert("XSS");</script>&b=UNION SELECT ALL FROM information_schema AND ' or SLEEP(5) or '&c=../../../../etc/passwd(URL编码前 )

从前面的流程可以看出,在def identwaf(self, findall=False):中调用的拼接的语句的方法就是本方法,拼接进三个语句,

其他的逻辑相同。

evillib.py分析

上面只是在上层对要拼接哪些参数进行构造,实际上组合成完整的 HTTP 报文调用requests.get()进行请求的是在该文件中。

wafw00f中若没有通过—headers指定头部的话,会使用自己默认的—headers这个默认的 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' #
        }

默认情况下,接下来通过requests.get()请求时便会使用该头部,

def Request(self, headers=None, path=None, params={}, delay=0, timeout=7):
    try:
       time.sleep(delay)
       if not headers:
           h = self.headers
       else: h = headers
       req = requests.get(self.target, proxies=self.proxies, headers=h, timeout=timeout,
                    allow_redirects=self.allowredir, params=params, verify=False)
       self.log.info('Request Succeeded')
       self.log.debug('Headers: %s\\n' % req.headers)
       self.log.debug('Content: %s\\n' % req.content)
       self.requestnumber += 1
       return req
     except requests.exceptions.RequestException as e:
            self.log.error('Something went wrong %s' % (e.__str__()))

指纹的识别

拿Huawei Cloud WAF的指纹来说

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

NAME = 'Huawei Cloud Firewall (Huawei)'

def is_waf(self):
    schemes = [
                
                # 匹配 cookie
        self.matchCookie(r'^HWWAFSESID='),
                # 匹配 header 中的 Server
        self.matchHeader(('Server', r'HuaweiCloudWAF')),
                # 匹配 body
        self.matchContent(r'hwclouds\\.com'),
        self.matchContent(r'hws_security@')
    ]
    if any(i for i in schemes):
        return True
    return False

CSDN使用华为云防护

1668779785_63778f0905b4c22ca27ee.png!small?1668779783711

其余脚本见:wafw00f/wafw00f/plugins at master · EnableSecurity/wafw00f

wafw00f 流量

1668779788_63778f0ccb052e89a938d.png!small?1668779787707
1668779791_63778f0faeaf4c7812b12.png!small?1668779790449

本文作者:Deutsh, 转载请注明来自FreeBuf.COM

责任编辑:武晓燕 来源: FreeBuf.COM

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK