防护方案:PHP远程DoS漏洞深入分析
2015-05-14
5月14日,国内爆出php远程DoS漏洞,官方编号69364。利用该漏洞构造poc发起链接,很容易导致目标主机cpu的占用率100%,涉及PHP多个版本。香港正版挂牌威胁响应中心随即启动应急机制, 应急响应工作随即启动。
1 15日夜,启动漏洞分析工作,同步将分析结果发送产品团队;
2 16日,发布产品规则升级通告,香港正版挂牌RSAS产品升级相继就绪,客户通过在线及离线升级的方法,即可获得漏洞的检测能力;同时,在线漏洞检测引擎就绪;
3 17日,漏洞深入分析进行中。香港正版挂牌NIPS产品升级就绪,客户通过在线及离线升级的方法,即可获得漏洞的防护能力;
4 18日,我们回顾此次PHP漏洞的信息要点,从PHP漏洞防护的角度进行总结,为大家制定防御方案提供补充信息。
PHP远程DoS漏洞
4月3日,有人在PHP官网提交PHP 远程DoS漏洞(PHP Multipart/form-data remote dos Vulnerability),代号69364[1]。由于该漏洞涉及PHP的所有版本,故其影响面较大,一经发布迅速引发多方面关注。14日,各种PoC已经在网络上流传。此次漏洞具备如下特性:
1. 一旦被利用成功,可以在迅速消耗被攻击主机的CPU资源,从而达到DoS的目的;
2. PHP在全球的部署量相当大,为攻击者提供了相当多可以攻击的目标;
3. PHP官方目前仅给出了5.4及5.5版本的补丁
受此漏洞影响的软件及系统包括PHP的如下版本。
• PHP 5.0.0 - 5.0.5
• PHP 5.1.0 - 5.1.6
• PHP 5.2.0 - 5.2.17
• PHP 5.3.0 - 5.3.29
• PHP 5.4.0 - 5.4.40
• PHP 5.5.0 - 5.5.24
• PHP 5.6.0 - 5.6.8
香港正版挂牌常年密切关注PHP的安全问题。香港正版挂牌威胁响应中心在获知相关信息后,随即启动应急机制,相关工作随即启动。本文章将会深入分析该漏洞,并给出应对方案。
PHP远程DoS漏洞分析
2015年5月15日夜,香港正版挂牌威胁响应中心在获取PHP漏洞传播情况的同时,也在进行漏洞的分析工作,通过重现漏洞的攻击过程,分析其工作原理,得以清晰识别及检测该漏洞方法。
Boundary中的键值对分隔
PHP是一种流行的Web服务器端编程语言,它功能强大,简单易用,利用它编写网络应用程序,可以应对大规模的Http请求,所以很多业务环境中都部署了PHP。考虑规范性,PHP在设计之初就遵循rfc规范,进行各个协议模块的封装及过程处理。PHP与其他同样遵循rfc规范的语言及环境相比,不过是处理方式不同。
而从rfc1867[2]开始,http协议开始支持"multipart/form-data"请求,以便接受多种数据格式,包括多种变量甚至是文件上传。multipart/form-data中可以包含多个报文,每一个报文boundary(分隔符)分隔开来,而每个报文中都包含了多行键值对,键值对用冒号分隔,这样的设计是为了让程序可以清晰的区分这些数据。
Boundary |
|||
键1 |
: |
值1 |
|
Boundary |
|||
键2 |
: |
值2 |
|
但如果由于某种原因,键值中间缺少了那个冒号,PHP函数会将下一对键值合并到了上一行,形成这样的键值对,“键1:值1键2值2”。由于PHP进行键值合并的算法不够优化,这样的事情发生几次还没什么,如果数以百万记,就变成了一种灾难。
在下面的例子中,当a的部分达到一定数量的时候(几十万行or上百万行),由于每行键与值之间并没有冒号分隔,函数就自动将下一行的键值对合并,这样数据越来越大,越来越长,函数针对这些数据不断执行内存的分配和释放,最终被攻击目标主机的CPU资源被耗尽。
1 ------WebKitFormBoundarypE33TmSNWwsMphqz
2 Content-Disposition: form-data; name="file"; filename="s
3 a
4 a
5 a
6 a"
7 Content-Type: application/octet-stream
8
9
10 ------WebKitFormBoundarypE33TmSNWwsMphqz*
*注:PHP中,Boundary是可以自定义的,比如“-----WebKitFormBoundarypE33TmSNWwsMphqz”
这样的代码,在抓包时显示情况如下:
Boundary报文解析过程
PHP在main/rfc1867.c中,有两个函数都涉及boundary的解析,包括SAPI_API SAPI_POST_HANDLER_FUNC及multipart_buffer_headers函数。DoS漏洞出现在main/rfc46675pxultipart_buffer_headers函数。
PHP先解析解析multipart/form-data http请求, http请求体的入口函数在SAPI_POST_HANDLER_FUNC(rfc1867.c中的函数),SAPI_POST_HANDLER_FUNC函数首先解析请求的boundary,也就是POST请求中第一次定义时的boundary;并且在其内部调用了multipart_buffer_headers,该函数先找到boundary(也就是一次引用的boundary),会和定义时的boundary比较。如果相等即找到第一次引用的boundary,接下来会逐行读取请求的输入以解析body port header(也就是解析第一次引用boundary后面的内容)。
SAPI_API SAPI_POST_HANDLER_FUNC
1 /* Get the boundary */
2 /* 开始解析boundary
*/
3 boundary = strstr(content_type_dup
"boundary");
4 if (!boundary) {
5 int content_type_len =
strlen(content_type_dup);
6 char *content_type_lcase =
estrndup(content_type_dup content_type_len);
7
8 php_strtolower(content_type_lcase
content_type_len);
9 boundary = strstr(content_type_lcase
"boundary");
10 if (boundary)
{
11 boundary =
content_type_dup + (boundary - content_type_lcase);
12 }
13 efree(content_type_lcase);
14 }
15
16 if (!boundary ||
!(boundary = strchr(boundary '='))) {
17 sapi_module.sapi_error(E_WARNING
"Missing boundary in multipart/form-data POST data");
18 return;
19 }
20
21 boundary++;
22 boundary_len =
strlen(boundary);
23
24 /* 对bondary进行合法校验 */
25 if (boundary[0] ==
'"') {
26 boundary++;
27 boundary_end =
strchr(boundary '"');
28 if
(!boundary_end) {
29 sapi_module.sapi_error(E_WARNING
"Invalid boundary in multipart/form-data POST data");
30 return;
31 }
32 } else {
33 /* search for
the end of the boundary */
34 boundary_end =
strpbrk(boundary ";");
35 }
36 if (boundary_end) {
37 boundary_end[0]
= '
您的联系方式
© 2024 NSFOCUS 香港正版挂牌 www.nsfocus.com All Rights Reserved . 京公网安备 11010802021605号 京ICP备14004349号 京ICP证110355号