Apache CVE-2017-7659漏洞重现及利用分析
近日,apache在其网站发布了最新的安全公告,其中涉及多个漏洞。针对CVE-2017-7659漏洞的介绍是这样的:
A maliciously constructedHTTP/2 request could cause mod_http2 to dereference a NULL pointer and crashthe server process.
可以看到这是apache WEB服务器(httpd)中的一个HTTP 2.0协议处理的漏洞。未然实验室安全研究人员针对此漏洞的技术细节和利用方法进行了深入的研究,欢迎安全爱好者们一起分享和讨论。
0×01补丁分析
在redhat的bugzilla上可以找到该漏洞:
https://bugzilla.redhat.com/show_bug.cgi?id=1463199
在github上有对该漏洞的修复提交:
https://github.com/apache/httpd/commit/672187c168b94b562d8065e08e2cad5b00cdd0e3
修改前后的代码差异比较如下:
可以看到,修复内容很简单,就是增加了对h2_request_rcreate函数返回值的判断。官方推荐升级到2.4.26修复漏洞。
0×02漏洞成因
从https://archive.apache.org/dist/httpd/httpd-2.4.25.tar.gz下载到有漏洞的服务器代码后,通过补丁的修改进行漏洞成因的逆向分析。
首先查看漏洞函数h2_stream_set_request_rec,发现是调用h2_request_rcreat创建http 2.0请求的数据结构req,h2_request_rcreat执行失败时req为空,此时在日志函数ap_log_rerror中直接解引用req导致进程崩溃:
继续查看函数h2_request_rcreate,看到首先会把req置为0,然后判断4个变量r->method,scheme,r->hostname,path,任何一个为空则返回失败,而此时req还是0,就会导致进程崩溃:
那么这4个变量是哪一个为空导致的漏洞呢?scheme是先判断了是否为空再赋值的,首先排除;path是从r->parsed_uri中解析出来,解析函数apr_uri_unparse在其它地方有多次使用,直觉path也不会为空;r->method保存请求的方法字段,在HTTP请求中必须存在,因此也不应该为空;因此只有r->hostname,保存请求的主机名,也就是域名,可能为空。
我们知道,HTTP请求中,有2个地方可以表示主机名:
1) 请求的路径以完整URL方式表示,URL中包含主机名,例如GET http://www.example.com/ HTTP/1.1,这里主机名就是www.example.com。服务器中是在ap_parse_uri函数中解析这种主机名的
2) 在Host请求头中包含主机名,例如:
GET / HTTP/1.1
Host: www.example.com
服务器中是在fix_hostname函数中解析这种主机名的
分别审计ap_parse_uri和fix_hostname函数,发现如果请求中没有Host头,那么r->hostname确实是空。但是服务器也考虑到了这种情况,在ap_read_request函数中做了判断:
这里的判断逻辑,如果满足下面2个条件之一
1) r->hostname为空,且请求的HTTP版本大于等于1.1
2) 没有Host头,且请求的HTTP版本等于1.1
就会立刻回复400状态码的错误页面,并不会触发后面的漏洞。在注释里也说明了,HTTP/1.1的RFC2616的14.23节中明确指明,HTTP/1.1请求必须包含Host头。
但是,开发者是不是忘了什么,HTTP还有1.0版本啊,且HTTP/1.0和HTTP/1.1的处理流程一样,虽然HTTP/1.0确实没有规定请求必须包含Host头。因此HTTP/1.0请求是可以没有Host头的,程序会一直按照流程执行,最终执行到h2_stream_set_request_rec函数,此时r->hostname为空,从而触发漏洞。
0×03漏洞验证及漏洞利用
综合上面的分析,该漏洞利用成功需要如下条件:
1) 服务器支持HTTP/2
2) 请求是HTTP/1.0版本
3) 请求中没有Host头
服务器配置
在server上要配置开启HTTP/2功能,使用apache默认的站点配置,在配置文件中首先加载mod_http2.so:
然后加入下面配置,重新启动apache httpd就可以了:
验证POC
验证时,我们首先起一个单一进程的apache httpd服务,方便验证进程崩溃后的效果:
正常访问,返回欢迎页面:
将构造的POC通过burpsuite发送:
近日,apache在其网站发布了最新的安全公告,其中涉及多个漏洞。针对CVE-2017-7659漏洞的介绍是这样的:
A maliciously constructedHTTP/2 request could cause mod_http2 to dereference a NULL pointer and crashthe server process.
可以看到这是apache WEB服务器(httpd)中的一个HTTP 2.0协议处理的漏洞。未然实验室安全研究人员针对此漏洞的技术细节和利用方法进行了深入的研究,欢迎安全爱好者们一起分享和讨论。
0×01补丁分析
在redhat的bugzilla上可以找到该漏洞:
https://bugzilla.redhat.com/show_bug.cgi?id=1463199
在github上有对该漏洞的修复提交:
https://github.com/apache/httpd/commit/672187c168b94b562d8065e08e2cad5b00cdd0e3
修改前后的代码差异比较如下:
copyright 无奈人生
可以看到,修复内容很简单,就是增加了对h2_request_rcreate函数返回值的判断。官方推荐升级到2.4.26修复漏洞。
0×02漏洞成因
从https://archive.apache.org/dist/httpd/httpd-2.4.25.tar.gz下载到有漏洞的服务器代码后,通过补丁的修改进行漏洞成因的逆向分析。
首先查看漏洞函数h2_stream_set_request_rec,发现是调用h2_request_rcreat创建http 2.0请求的数据结构req,h2_request_rcreat执行失败时req为空,此时在日志函数ap_log_rerror中直接解引用req导致进程崩溃:
继续查看函数h2_request_rcreate,看到首先会把req置为0,然后判断4个变量r->method,scheme,r->hostname,path,任何一个为空则返回失败,而此时req还是0,就会导致进程崩溃:
那么这4个变量是哪一个为空导致的漏洞呢?scheme是先判断了是否为空再赋值的,首先排除;path是从r->parsed_uri中解析出来,解析函数apr_uri_unparse在其它地方有多次使用,直觉path也不会为空;r->method保存请求的方法字段,在HTTP请求中必须存在,因此也不应该为空;因此只有r->hostname,保存请求的主机名,也就是域名,可能为空。
无奈人生安全网
我们知道,HTTP请求中,有2个地方可以表示主机名:
1) 请求的路径以完整URL方式表示,URL中包含主机名,例如GET http://www.example.com/ HTTP/1.1,这里主机名就是www.example.com。服务器中是在ap_parse_uri函数中解析这种主机名的
2) 在Host请求头中包含主机名,例如:
GET / HTTP/1.1
Host: www.example.com
服务器中是在fix_hostname函数中解析这种主机名的
分别审计ap_parse_uri和fix_hostname函数,发现如果请求中没有Host头,那么r->hostname确实是空。但是服务器也考虑到了这种情况,在ap_read_request函数中做了判断:
这里的判断逻辑,如果满足下面2个条件之一
1) r->hostname为空,且请求的HTTP版本大于等于1.1
2) 没有Host头,且请求的HTTP版本等于1.1
就会立刻回复400状态码的错误页面,并不会触发后面的漏洞。在注释里也说明了,HTTP/1.1的RFC2616的14.23节中明确指明,HTTP/1.1请求必须包含Host头。
但是,开发者是不是忘了什么,HTTP还有1.0版本啊,且HTTP/1.0和HTTP/1.1的处理流程一样,虽然HTTP/1.0确实没有规定请求必须包含Host头。因此HTTP/1.0请求是可以没有Host头的,程序会一直按照流程执行,最终执行到h2_stream_set_request_rec函数,此时r->hostname为空,从而触发漏洞。
无奈人生安全网
0×03漏洞验证及漏洞利用
综合上面的分析,该漏洞利用成功需要如下条件:
1) 服务器支持HTTP/2
2) 请求是HTTP/1.0版本
3) 请求中没有Host头
服务器配置
在server上要配置开启HTTP/2功能,使用apache默认的站点配置,在配置文件中首先加载mod_http2.so:
然后加入下面配置,重新启动apache httpd就可以了:
验证POC
验证时,我们首先起一个单一进程的apache httpd服务,方便验证进程崩溃后的效果:
正常访问,返回欢迎页面:
copyright 无奈人生
将构造的POC通过burpsuite发送:
本文来自无奈人生安全网