|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
Patchespatch-5.4 (last revision 2015-05-10 06:00 UTC by stas@php.net)Pull RequestsHistoryAllCommentsChangesGit/SVN commits
[2015-05-07 07:45 UTC] liushusheng at baidu dot com
[2015-05-07 07:49 UTC] stas@php.net
[2015-05-10 06:00 UTC] stas@php.net
[2015-05-10 06:03 UTC] stas@php.net
[2015-05-12 04:49 UTC] liushusheng at baidu dot com
[2015-05-12 05:15 UTC] stas@php.net
[2015-05-12 05:43 UTC] liushusheng at baidu dot com
[2015-05-12 19:40 UTC] stas@php.net
[2015-05-12 19:40 UTC] stas@php.net
-Status: Open
+Status: Closed
[2015-05-12 22:58 UTC] stas@php.net
[2015-05-13 10:53 UTC] jpauli@php.net
[2015-05-15 05:37 UTC] laruence@php.net
-Assigned To:
+Assigned To: laruence
[2015-05-15 05:37 UTC] laruence@php.net
[2015-05-15 05:42 UTC] stas@php.net
[2015-05-15 05:45 UTC] liushusheng at baidu dot com
[2015-05-15 05:46 UTC] liushusheng at baidu dot com
[2015-05-15 13:40 UTC] laruence@php.net
-Assigned To: laruence
+Assigned To: stas
[2015-05-15 13:40 UTC] laruence@php.net
[2015-05-15 15:07 UTC] kaplan@php.net
[2015-05-19 03:04 UTC] welpher dot yu at gmail dot com
[2015-05-19 03:47 UTC] stas@php.net
[2015-05-19 05:32 UTC] laruence@php.net
-CVE-ID:
+CVE-ID: 2015-4024
[2015-05-20 03:07 UTC] mrbaiwei at gmail dot com
[2015-05-20 03:38 UTC] czxin788 at qq dot com
[2015-05-20 08:20 UTC] lishaobang at nawang dot cn
[2015-05-21 02:05 UTC] 376166899 at qq dot com
[2015-05-21 05:00 UTC] rasmus@php.net
[2015-05-21 07:01 UTC] blackhat2014 at 163 dot com
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Tue Oct 28 23:00:01 2025 UTC |
Description: ------------ PHP Multipart/form-data remote dos Vulnerability Author: Shusheng Liu, The Department of Security Cloud, Baidu,China 1. Description: PHP is vulnerable to a remote denial of service, caused by repeatedly allocate memory、concatenate string、copy string and free memory when PHP parses header areas of body part of HTTP request with multipart/form-data. By sending multiple HTTP multipart requests to an affected application containing malicious header area of body part, a remote attacker could exploit this vulnerability to cause the consumption of CPU resources. 2. Analysis 2.1. Entry-point of The Remote Denial of Service Vulnerability The vulnerable function is multipart_buffer_headers that is called internally by the function SAPI_POST_HANDLER_FUNC in main/rfc1867.c. SAPI_POST_HANDLER_FUNC is the entry-point function which parses body parts of HTTP request with multipart/form-data. There is a remote denial of service vulnerability when multipart_buffer_headers is called. The source code of the multipart_buffer_headers function is shown as follows: ------------------------------------------------------------------------------------------------------------------- /* 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; } --------------------------------------------------------------------------------------------------------------- 2.2 Analyze The Vulnerable Function Now, we detailedly analyze logic of multipart_buffer_headers, and then we prove denial of service vulnerability of multipart_buffer_headers. Step 1. The multipart_buffer_headers executes while loop cycle to parse current body part headers, if the boundary string was found. while( (line = get_line(self TSRMLS_CC)) && line[0] != '\0') Step 2. Step 2.1. When parseing current body part headers which is represented as (header, value), the multipart_buffer_headers function firstly call get_line function to read a line of characters, but get_line return a line when it meets character '\n', not '\r\n'. After getting a line which is stored in the variable 'line', the multipart_buffer_headers function parses the variable line. Step 2.2. If the first character of the line is blank character (corresponding code "if (!isspace(line[0]))"), or the variable line contains character ':', the multipart_buffer_headers function successfully parse a header pair that is represented as entry=(header,value). And then, it calls zend_llist_add_element function to store entry, and use variable prev_entry to record lastest parsed name value pair entry. After that , it go to next cycle. Step 2.3. In this step, the multipart_buffer_headers function thinks current line is not a new header, and current line should be append to value of prev_entry. Thus, prev_entry and current line merge into a new entry by executing the following codes: ------------------------------------------------------------------------------------------------------------------------ prev_len = strlen(prev_entry.value); cur_len = strlen(line); entry.value = emalloc(prev_len + cur_len + 1); //allocate (prev_len + cur_len) bytes memory. memcpy(entry.value, prev_entry.value, prev_len); //copy prev_len bytes. memcpy(entry.value + prev_len, line, cur_len); // cope (prev_len + cur_len) bytes memory. entry.value[cur_len + prev_len] = '\0'; entry.key = estrdup(prev_entry.key); zend_llist_remove_tail(header); // free memory ---------------------------------------------------------------------------------------------------------------------- 2.3 The Remote Denial of Service Vulnerability If value of body part header consists of n lines, and first character of each line is not blank character, and each line did constains character ':', the multipart_buffer_headers function executes Step 2.3 (n-1) times when the multipart_buffer_headers function parse the header. The block of code allocates memory once, executes string copy operation twice, frees memory once. Each time mergence of entry.value increase length of body part header's value, thus string copy operations will cause the consumption of CPU resources, and then the service is not available. If n is the length of body part header's value, and copying one byte is the unit time complexity,the time complexity of multipart_buffer_headers function is O(n*m). For example: ------WebKitFormBoundarypE33TmSNWwsMphqz Content-Disposition: form-data; name="file"; filename="s a a a a" Content-Type: application/octet-stream <?php phpinfo();?> ------WebKitFormBoundarypE33TmSNWwsMphqz The value of Content-Disposition consists of 5 lines, and the length of the value of Content-Disposition is 5. The multipart_buffer_headers function executes Step 2.3 4 times. The first time execution copys 2 bytes, The second execution copys 3 bytes, The third time execution copys 4 bytes, The fourth time execution copys 5 bytes. Thus, the multipart_buffer_headers function executes 14 times byte copy operation. Default maximum size of body part is 2097152 bytes (2M), It is enough to cause the consumption of CPU resources by sending multiple HTTP multipart requests to an affected application containing malicious header area of body part. Test script: --------------- The poc was sent to the email security@php.net by liushusheng@baidu.com. Expected result: ---------------- Poc prints response time of a dos-attack request。response time of the dos-attack request more than 5 seconds.