PHP远程DoS漏洞深入分析 及防护方案
执行摘要
5月14日,国内爆出php远程DoS漏洞,官方编号69364。利用该漏洞构造poc发起链接,很容易导致目标主机cpu的占用率100%,涉及PHP多个版本。绿盟科技威胁响应中心随即启动应急机制, 应急响应工作随即启动。- 15日夜,启动漏洞分析工作,同步将分析结果发送产品团队;
- 16日,发布产品规则升级通告,绿盟科技RSAS产品升级相继就绪,客户通过在线及离线升级的方法,即可获得漏洞的检测能力;同时,在线漏洞检测引擎就绪;
- 17日,漏洞深入分析进行中。绿盟科技NIPS产品升级就绪,客户通过在线及离线升级的方法,即可获得漏洞的防护能力;
- 18日,我们回顾此次PHP漏洞的信息要点,从PHP漏洞防护的角度进行总结,为大家制定防御方案提供补充信息。
- 绿盟科技威胁响应中心微博 :http://weibo.com/threatresponse
- 绿盟科技微博:http://weibo.com/nsfocus
- 绿盟科技微信号:搜索公众号 绿盟科技
PHP远程DoS漏洞
4月3日,有人在PHP官网提交PHP 远程DoS漏洞(PHP Multipart/form-data remote dos Vulnerability),代号69364。由于该漏洞涉及PHP的所有版本,故其影响面较大,一经发布迅速引发多方面关注。14日,各种PoC已经在网络上流传。此次漏洞具备如下特性:- 一旦被利用成功,可以在迅速消耗被攻击主机的CPU资源,从而达到DoS的目的;
- PHP在全球的部署量相当大,为攻击者提供了相当多可以攻击的目标;
- PHP官方目前仅给出了5.4及5.5版本的补丁
- 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远程DoS漏洞分析
2015年5月15日夜,绿盟科技威胁响应中心在获取PHP漏洞传播情况的同时,也在进行漏洞的分析工作,通过重现漏洞的攻击过程,分析其工作原理,得以清晰识别及检测该漏洞方法。 Boundary中的键值对分隔 PHP是一种流行的Web服务器端编程语言,它功能强大,简单易用,利用它编写网络应用程序,可以应对大规模的Http请求,所以很多业务环境中都部署了PHP。考虑规范性,PHP在设计之初就遵循rfc规范,进行各个协议模块的封装及过程处理。PHP与其他同样遵循rfc规范的语言及环境相比,不过是处理方式不同。 而从rfc1867开始,http协议开始支持"multipart/form-data"请求,以便接受多种数据格式,包括多种变量甚至是文件上传。multipart/form-data中可以包含多个报文,每一个报文boundary(分隔符)分隔开来,而每个报文中都包含了多行键值对,键值对用冒号分隔,这样的设计是为了让程序可以清晰的区分这些数据。


- /* Get the boundary */
- /* 开始解析boundary */
- boundary = strstr(content_type_dup, "boundary");
- if (!boundary) {
- int content_type_len = strlen(content_type_dup);
- char *content_type_lcase = estrndup(content_type_dup, content_type_len);
- php_strtolower(content_type_lcase, content_type_len);
- boundary = strstr(content_type_lcase, "boundary");
- if (boundary) {
- boundary = content_type_dup + (boundary - content_type_lcase);
- }
- efree(content_type_lcase);
- }
- if (!boundary || !(boundary = strchr(boundary, '='))) {
- sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
- return;
- }
- boundary++;
- boundary_len = strlen(boundary);
- /* 对bondary进行合法校验 */
- if (boundary[0] == '"') {
- boundary++;
- boundary_end = strchr(boundary, '"');
- if (!boundary_end) {
- sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
- return;
- }
- } else {
- /* search for the end of the boundary */
- boundary_end = strpbrk(boundary, ",;");
- }
- if (boundary_end) {
- boundary_end[0] = '\0';
- boundary_len = boundary_end-boundary;
- }
- /* Initialize the buffer */
- if (!(mbuff = multipart_buffer_new(boundary, boundary_len TSRMLS_CC))) {
- sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
- return;
- }
- while (!multipart_buffer_eof(mbuff TSRMLS_CC))
- {
- char buff[FILLUNIT];
- char *cd = NULL, *param = NULL, *filename = NULL, *tmp = NULL;
- size_t blen = 0, wlen = 0;
- off_t offset;
- zend_llist_clean(&header);
- /* 漏洞函数 */
- if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
- goto fileupload_done;
- }
- /* parse headers */
- static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
- {
- char *line;
- mime_header_entry prev_entry = {0}, entry;
- int prev_len, cur_len;
- /* didn't find boundary, abort */
- if (!find_boundary(self, self->boundary TSRMLS_CC)) {
- return 0;
- }
- /* get lines of text, or CRLF_CRLF */
- /* 逐行解析 */
- while( (line = get_line(self TSRMLS_CC)) && line[0] != '\0' )
- {
- /* add header to table */
- char *key = line;
- char *value = NULL;
- if (php_rfc1867_encoding_translation(TSRMLS_C)) {
- self->input_encoding = zend_multibyte_encoding_detector(line, strlen(line), self->detect_order, self->detect_order_size TSRMLS_CC);
- }
- /* space in the beginning means same header */
- /* 如果该行开头不是空格,则试图寻找':'查看是否是有效键值对 */
- if (!isspace(line[0])) {
- value = strchr(line, ':');
- }
- /* 如果找到':'则说明该行包含一个有效的键值对,解析它 */
- if (value) {
- *value = 0;
- do { value++; } while(isspace(*value));
- entry.value = estrdup(value);
- entry.key = estrdup(key);
- /* 如果不包含':',且该行前有一个有效键值对,则说明这一行是上一个键值对的值 */
- } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */
- prev_len = strlen(prev_entry.value);
- cur_len = strlen(line);
- /* 进行值合并操作 */
- entry.value = emalloc(prev_len + cur_len + 1);
- memcpy(entry.value, prev_entry.value, prev_len);
- memcpy(entry.value + prev_len, line, cur_len);
- entry.value[cur_len + prev_len] = '\0';
- entry.key = estrdup(prev_entry.key);
- zend_llist_remove_tail(header);
- } else {
- continue;
- }
- zend_llist_add_element(header, &entry);
- prev_entry = entry;
- }
- return 1;
- }
- entry.value = emalloc(prev_len + cur_len + 1);
- memcpy(entry.value, prev_entry.value, prev_len);
- memcpy(entry.value + prev_len, line, cur_len);
- zend_llist_remove_tail(header);
PHP远程DoS漏洞检测
面对如此简单的漏洞利用,以及较低的攻击门槛,分析人员迅速将经过安全验证后的检测方法向云端、产品端及服务端传递,并建议用户尽快对其业务环境进行一次全面的漏洞检测,以便可以尽快拿到第一手数据,为后续制定漏洞防护方案及执行措施提供数据支撑及决策依据。 云端检测 5月16日晚,绿盟科技客户自助门户系统Portal发布PHP远程DoS漏洞检测引擎,为PHP Multipart/form-data远程DoS漏洞(PHP-69364)提供扫描支持。


PHP远程DoS漏洞防护
知道了漏洞利用方法,也知道了攻击检测方法,那么漏洞的防护也就知道该如何做了。如果确认您的业务环境中存在这个漏洞,那么就需要参考上面的信息,尽快制定并启动加固方案,这些加固从漏洞补丁开始,到产品防护,到整体防护,逐步推进。 漏洞加固 PHP官方已经针对PHP 5.4 及PHP 5.5版本给出了补丁,请使用这些版本的用户,尽快到官方网站下载并安装补丁,补丁的下载地址如下: http://php.net/ChangeLog-5.php#5.4.41 http://php.net/ChangeLog-5.php#5.5.25


威胁情报
从此次PHP远程DoS漏洞情况可以看到,无论漏洞原理怎样,无论漏洞防护方案如何实施,关键在于尽可能快的了解到漏洞信息及相关的情报,以便尽可能快的启动应急响应机制。这无论对于解决传统安全或者APT攻击来说都是重要的手段之一,威胁情报的获取及响应都体现了防御能力的建设程度,威胁情报服务体系至少包含了威胁监测及响应、数据分析及整理、业务情报及交付、风险评估及咨询、安全托管及应用等各个方面,涉及研究、产品、服务、运营及营销的各个环节,绿盟科技通过研究、云端、产品、服务等立体的应急响应体系,向企业和组织及时提供威胁情报并持续进行后续服务,保障客户业务的顺畅运行。 如果您对我们提供的内容有任何疑问,或者需要了解更多的信息,可以随时通过在微博、微信中搜索绿盟科技联系我们,欢迎您的垂询!关于绿盟科技

关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

随时掌握互联网精彩
赞助链接
排名
热点
搜索指数
- 1 总书记寄语劳动者 7904678
- 2 前央视主持人被曝转行养鸡 7808576
- 3 巴菲特分享赚钱秘诀 7713800
- 4 解锁五一假期的N种玩法 7619412
- 5 女生手机自动连上酒店WiFi被分手 7524042
- 6 中国驻日本大使向日方提出严正交涉 7427582
- 7 44岁郭晶晶出席活动女王气场全开 7331224
- 8 巴菲特计划在年底退休 7237436
- 9 马丽回应与沈腾cp被过分关注 7140388
- 10 五一假期天安门广场游人如织 7044846