Author:dawu(知道創宇404實驗室)

date: 2016-11-16

0x00 漏洞概述

1.漏洞簡介

Sparkjava是一款小型的web框架,它能夠讓你以很少的代碼構建出一個java web應用。近日,某國外安全研究人員發現其存在文件遍歷漏洞,可以通過該漏洞讀取任意文件內容。在對這個漏洞進行復現與分析的時候,我們又發現了一些可能可以利用的地方,但是利用條件更加苛刻。

2.漏洞影響

Sparkjava版本 < 2.5.2

0x01 漏洞復現

1.驗證環境

Jdk-1.8.0_111 Apache maven 3.3.9 在寫好Sparkjava代碼后,在文件所在目錄打開命令行,運行mvn package進行編譯打包。

2.漏洞復現

根據官網給出的示例,我們寫了一個簡單的函數去復現這個漏洞:

public class Hello {

    public static void main(String[] args) {
        staticFiles.externalLocation(“/tmp”);
        get("/", (req, res) -> {
            return "hello from sparkjava.com";
        });
    }
}

pom.xml的配置為

<dependency>
    <groupId>com.sparkjava</groupId>
    <artifactId>spark-core</artifactId>
    <version>2.5</version>
</dependency>

這里提供已經打包好的jar文件供大家下載。可以用如下命令運行:

java -jar sparkexample-jar-with-dependencies.jar

我們可以通過(..\)來改變路徑從而讀取任意文件。如圖,我們讀取到/etc/passwd: 復現 在漏洞發現者的描述中,Spark.staticFileLocation()和Spark.externalStaticFileLocation()這兩個函數都存在這個問題。經過開發者測試,在IDE中運行時,兩個函數都可以復現這個漏洞;運行打包好的jar包時,只有Spark.externalStaticFileLocation()這個函數可以觸發漏洞。

0x02 補丁分析與深入研究

1.補丁分析

很明顯,在漏洞被發現時,官方沒有對url中的路徑做任何處理。在漏洞被修補之后,官方推出了新的版本2.5.2。這里我們對比之前的版本,并且通過調試,嘗試分析官方的修補方案。 官方修補鏈接(https://github.com/perwendel/spark/commit/efcb46c710e3f56805b9257a63d1306882f4faf9) 當我們正常請求時:

curl "127.0.0.1:4567/l.txt"

跟到關鍵代碼處,我們可以看到在判斷文件是否存在之后,官方添加了DirectoryTraversal.protectAgainstInClassPath(resource.getPath());進行判斷。 動態調試1 這里,path就是我們HTTP請求的地址,addedPath就是我們通過staticFiles.externalLocation()函數設置的路徑與path拼接之后的值,resource中的file的值就是addedPath值經過路徑的處理的值(例如:/tmp/test/..\l.txt先將所有的\換成/,再對路徑進行處理,最后結果為/tmp/l.txt),resource.getPath()就是addedPath的值。

動態調試2

protectAgainstInClassPath()函數中,需要判斷removeLeadingAndTrailingSlashesFrom(path).startsWith(StaticFilesFolder.external())是否為false,為false就拋出。

removeLeadingAndTrailingSlashesFrom(path)為新添加的函數,作用是將path首尾的/去掉和將尾部的\去掉。在這里經過處理之后,path的值為tmp/l.txt

StaticFilesFolder.external()則是返回external的值,在這里就是tmp。如果removeLeadingAndTrailingSlashesFrom(path)前面的字母是tmp,則進入下一步。

綜上所述,官方通過比較經過處理后的路徑的開頭和我們設置的externalLocation()的路徑是否相同來防止我們利用..\讀取任意文件。

2.深入探究

我們修改了pom.xml,使用新的Sparkjava版本進行編譯嘗試,做了如下探究。

<dependency>
    <groupId>com.sparkjava</groupId>
    <artifactId>spark-core</artifactId>
    <version>2.5.2</version>
</dependency>

① 軟鏈接的利用

與Sparkjava(CVE-2016-9177)同時爆出來的一個漏洞GitLab的任意文件讀取(CVE-2016-9086)是利用軟鏈接的特性,我們就順手測試了軟鏈接在Sparkjava下的利用。 直接讀取文件: file 路徑映射: path 怎么才能利用軟鏈接呢?這里的利用條件比較苛刻。筆者想到了兩種途徑: 1.網站允許上傳壓縮包,上傳后解壓并且還能訪問到解壓后的文件才能利用 2.網站通過wget(wget配置文件中需要retr-symlinks=on)從ftp上下載文件并且能夠訪問到下載的文件。

②再次讀取文件

我們在根目錄下新建兩個文件tmp.txt,tmp2.txt tmp 再訪問 tmp 讀取到了tmp.txt和tmp2.txt的內容。 我們分析一下能夠再次讀取的原因,當我們請求為:

curl “127.0.0.1:4567/tmp\..\..\tmp.txt”

分析過濾代碼處: read addedPath的值為/tmp/tmp/..\..\tmp.txt,經過處理后resource中的file值為/tmp.txt,對于下面的函數removeLeadingAndTrailingSlashesFrom(path).startsWith(StaticFilesFolder.external()),由于tmp.txt也是由tmp開頭,所以判斷可以通過,進而讀取到tmp.txt

同樣的道理,我們也可以讀取到/tmp2/test.txt的內容。 tmp3

通過以上分析,筆者認為這個讀取很雞肋,首先staticFiles.externalLocation()中定義的路徑只能是一級路徑,其次我們要讀取的文件的完整路徑開頭必須和staticFiles.externalLocation()中定義的路徑相同。這就限制了這個新的讀取,也許只有在某些特定的場合才能有奇效。

如有錯誤,歡迎指正:)

0x03 參考鏈接


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/115/