天天看點

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

這個洞出來也有一段時間了,看了創宇的paper後覺得蠻簡單的,決定自己在本地搭建複現一下,記錄一下學習的過程。

環境準備

apache + thinphp(<=6.0.0版本<=6.0.2) + php7以上

  • ThinkPHP6起隻能使用composer來安裝,安裝composer、php、apache的過程我就不贅述了。

    執行指令:

    composer create-project topthink/think tp 6.0.0

    ,其中tp是你的檔案夾命名,6.0.0是版本号,6.0.1也可。

    這裡說一個問題,我這個時間Thinkphp的最新版是6.0.2,用上面的指令下載下傳下來framework是6.0.2版本的,我們需要再執行一條指令:

    composer require topthink/framework:6.0.0

    :此時就會把将6.0.0的版本把6.0.2給替換掉
  • 進入tp的安裝目錄,執行

    php think run

    ,它會開啟一個臨時的開發環境的伺服器,預設運作在

    localhost:8000

    ,打開浏覽器通路顯示正常即可
漏洞複現在apache下進行

漏洞分析

漏洞影響的版本:top-think/framework 6.x < 6.0.2

  • 官方資訊

    ThinkPHP釋出的更新檔聲稱修複了一處由于不安全的SessionId導緻的任意檔案操作漏洞:在開啟Session的情況下可以導緻建立任意檔案以及删除任意檔案,特定情況下可以getshell

  • 根據這些資訊,我們到官方GitHub的commit頁面找一下相關的送出記錄:
    ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

可以看到位于src/think/session/Store.php中212行在設定

id

時增加了一個函數:

ctype_alnum($text)

查一下PHP官方手冊,這個函數是用來檢測輸入的

$text

中所有的字元全部是字母和(或者)數字,傳回 TRUE 否則傳回FALSE

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

根據檔案目錄和更改的函數部分猜測:可能是存儲Session時導緻的檔案寫入;然後跟進找一下相關的函數,可以看到

vendor/topthink/framework/src/think/session/Store.php:254

的save()函數,265行還可以對檔案進行删除操作,并且對後端業務邏輯依賴較低

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

可以看到設定了$sessionId,并且調用了一個write函數,繼續跟進,找到write()函數

vendor/topthink/framework/src/think/session/driver/File.php:210

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

繼續跟進,找到writeFile()函數

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

可以看到調用了

file_put_contents()

函數,這裡是真正寫入檔案的操作了

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現
  • 接下來我們反向分析一下,看看能不能找到可控點
  1. 函數

    file_put_contents($path,$content,LOCK_EX)

    中參數

    $path,$content

    來源于函數

    writeFile($path,$data)

  2. 函數

    writeFile($path,$data)

    中參數

    $path,$data

    來源于函數

    write(String $sessionID,String $sessiData)

  3. 函數

    write(String $sessionID,String $sessiData)

    中參數

    $sessionID,$sessiData

    來源于

    save()

    中調用了

    write()

    ,同時傳入的參數

    $sessionId

    的值是調用

    getId()

    傳入的

    綜上:檔案名來源于

    $sessionId

  • 當傳入的id值長度為32并且…etc時,建立

    sessionId

    ,然後進行

    gitId()

    ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現
  • 接下來找調用

    setId()

    的地方

    vendor/topthink/framework/src/think/middleware/SessionInit.php:46

    ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

其中

cookieName

的值為

PHPSESSID

,而

$sessionId

cookie

中名為

PHPSESSID

的值,是以是攻擊者可控的,進而導緻寫入的檔案名可控。

但是預設環境下,

session

的内容由

vendor/topthink/framework/src/think/session/Store.php:261

的變量

$data

傳入:

$data

在預設環境中為空:

/**
     * Session資料
     * @var array
     */
    protected $data = [];
           

寫入的

session

内容是由實際的後端業務邏輯來決定的,是以說隻有苛刻的條件下才能寫入webshell。并且一開始就說了需要在環境開啟

session

的情況下才可以實作任意檔案操作(預設環境不開啟session)

  • 我們在

    app\controller\index.php

    中增加一些代碼後,如下:
<?php

namespace app\controller;

use think\facade\Session;
use app\BaseController;

class Index extends BaseController
{
    public function index()
    {
        Session::set('name','thinkphp');
        return 1;
        return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V6<br/><span style="font-size:30px">13載初心不改 - 你值得信賴的PHP架構</span></p></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="eab4b9f840753f8e7"></think>';
    }

    public function hello($name = 'ThinkPHP6')
    {
        return 'hello,' . $name;
    }
}

           
忘了說了thinkphp6開啟session的方法:删除

/app/middleware.php

最後一行的注釋
ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

本地環境複現

很簡單,隻需要構造PHPSESSID的值即可,值為

string

&&長度為32

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

此時檢視一下生成的session,生成的session檔案儲存在

\runtime\session

ThinkPHP6任意檔案操作漏洞分析環境準備漏洞分析本地環境複現

session裡的内容:

可以看到session的内容經過了序列化操作,隻要将session的内容反序列化即可getshell

  • 如果要getshell的話,後端需要有類似的

    Session::Set('name',$_POST['i'])

    代碼才可以利用

總結:

在複現的過程,也遇到了不少問題:首先ThinkPHP6開始不支援git了,隻能通過composer來操作,由于從來沒用過它也沒經驗,一開始安裝環境一直下載下傳不到舊版本,後來得到師傅的幫助終于下好了ThinkPHP6.0.0的環境,在這裡感謝一下師傅@P1an0對我的幫助。

這個漏洞其實很簡單,就是使用者可控變量導緻的,也沒有對一些資料的過濾等等。需要一定條件才可以利用,也就是開啟session;寫webshell還要看具體的後端業務邏輯等等。我覺得就這個架構來看其實可以更深入的進行挖掘,希望有大佬可以和我一起探讨學習

參考的paper:ThinkPHP6 任意檔案操作漏洞分析