
CtrlPanel Web インストーラーの CVE-2026-34234 認証されていない RCE を実証するローカル Docker ラボ。脆弱なコンテナとパッチ適用済みコンテナ、PoC スクリプト、根本原因分析が含まれ、セキュリティ調査と防御的検証に役立ちます。
CtrlPanel の CVE-2026-34234 を実証するためのローカル Docker ラボです。
このリポジトリは以下を比較します:
vuln: ダイジェストで固定された CtrlPanel 1.1.1patched: ダイジェストで固定された CtrlPanel 1.2.0このラボはローカルのみで動作し、サービスは 127.0.0.1 にバインドされます。
CVE-2026-34234 は、CtrlPanel の Web インストーラーにおける認証なし RCE です。
この問題は、2つのバグが連鎖することで発生します:
install.lock によるゲートの前に、インストーラーのフォームハンドラーに到達できた。このラボでは、脆弱なコンテナが無害な証明コマンドを実行し、その出力をコンテナ内に書き込みます。パッチ適用済みコンテナは同じリクエストを受け取りますが、証明ファイルは作成されません。
期待される結果:
vulnerable => proof file created
patched => no proof file
1.1.1 における脆弱なシェル実行元の脆弱なファイル:
public/installer/src/functions/shell.php
1.1.1 の関連するアップストリームコード:
function run_console(string $command, ...) {
$path = dirname(__DIR__, 4);
$handle = proc_open("cd '$path' && bash -c 'exec -a ServerCPP $command'", ...);
}
問題点:
run_console() は1つのシェルコマンド文字列を受け取ります。bash -c に渡されます。元の脆弱なファイル:
public/installer/src/forms/pterodactyl.php
1.1.1 の関連するアップストリームの動作:
run_console("php artisan settings:set 'PterodactylSettings' 'panel_url' '$url'", ...);
run_console("php artisan settings:set 'PterodactylSettings' 'admin_token' '$key'", ...);
run_console("php artisan settings:set 'PterodactylSettings' 'user_token' '$clientkey'", ...);
問題点:
url、key、clientkey はインストーラーの POST データに由来します。アドバイザリによると、public/installer/index.php はインストーラーのフォームロジックを読み込んで実行した後にのみ install.lock をチェックしていました。そのため、インストール済みのインスタンスでもインストーラーのハンドラーに到達可能でした。
修正では、install.lock のチェックをフォームハンドラーの読み込み前に移動します。
パッチ適用後の動作:
if (file_exists('../../install.lock')) {
exit("The installation has been completed already. Please delete the File 'install.lock' to re-run");
}
元のパッチ適用済みファイル:
public/installer/src/functions/shell.php
1.2.0 の関連するアップストリームコード:
function run_console(array $command, ...): string {
$cwd = $cwd ?? $path;
$handle = proc_open($command, $descriptors, $pipes, $cwd, null, $options);
}
これで問題が修正される理由:
run_console() は argv 形式の配列を受け取るようになりました。$() のようなペイロード構文は、シェル構文ではなくリテラル入力として扱われます。1.2.0 のパッチ適用済みフォームの動作では、配列形式のコマンド実行を使用します:
run_console(['php', 'artisan', 'settings:set', 'PterodactylSettings', 'panel_url', $url], ...);
run_console(['php', 'artisan', 'settings:set', 'PterodactylSettings', 'admin_token', $key], ...);
run_console(['php', 'artisan', 'settings:set', 'PterodactylSettings', 'user_token', $clientkey], ...);
127.0.0.1:8081 -> vulnerable CtrlPanel 1.1.1
127.0.0.1:8082 -> patched CtrlPanel 1.2.0
127.0.0.1:9100 -> fake Pterodactyl API
サービス:
vuln: 実際の CtrlPanel 1.1.1patched: 実際の CtrlPanel 1.2.0fake-api: インストーラーのチェックを満たすためだけに使用されるローカル疑似 Pterodactyl APImysql_vuln / mysql_patched: 独立した MariaDB インスタンスredis_vuln / redis_patched: 独立した Redis インスタンスこのラボは CtrlPanel アプリケーションのソースコードを変更しません。
Dockerfile は、元のコンテナのエントリポイントをラップして、以下の Docker Desktop ランタイム権限を正規化するだけです:
/var/www/html/storage
/var/www/html/bootstrap/cache
権限を修正した後、ラッパーは元の製品エントリポイントを実行します。
主要な PoC:
poc/poc_http_only.py
特性:
docker exec を使用しないid、whoami、hostnameヘルパースクリプト:
poc/poc_lab.py
目的:
docker compose exec を使用してコンテナ内の証明を検証アプリコンテナ内の証明ファイル:
/var/www/html/storage/logs/cve_2026_34234_proof.txt
クリーンなラボ状態から開始:
docker compose down -v --remove-orphans
docker compose up -d --build
アプリコンテナが起動するまで待ってから、次を実行:
python3 poc/poc_lab.py
期待される出力:
== Testing vulnerable ==
proof_exists: True
result: PASS expected_proof=True
== Testing patched ==
proof_exists: False
result: PASS expected_proof=False
[+] Expected result reached:
vulnerable => proof file created
patched => no proof file
HTTP のみの PoC を脆弱なターゲットに送信:
python3 poc/poc_http_only.py --target http://127.0.0.1:8081
証明を手動で確認:
docker compose exec vuln sh -lc 'cat /var/www/html/storage/logs/cve_2026_34234_proof.txt'
期待される証明:
uid=1000(laravel) gid=1000(laravel) groups=1000(laravel)
laravel
<container-hostname>
同じリクエストをパッチ適用済みに対して実行:
python3 poc/poc_http_only.py --target http://127.0.0.1:8082
パッチ適用済みの動作を確認:
docker compose exec patched sh -lc 'test -f /var/www/html/storage/logs/cve_2026_34234_proof.txt && cat /var/www/html/storage/logs/cve_2026_34234_proof.txt || echo "no proof file"'
期待される結果:
no proof file
コンテナ、ネットワーク、ラボのボリュームを削除:
docker compose down -v
このリポジトリは、教育目的のセキュリティ研究および防御的検証のためにのみ提供されます。
すべてのデモは、提供されたローカル Docker ラボ環境内での実行を意図しています。概念実証は、破壊的な操作、永続化、認証情報の窃取、データの外部送信、実際のシステムへの標的設定を回避しています。
明示的な許可なしに、このプロジェクトをいかなるシステムに対しても使用しないでください。著者は、この資料の悪用またはそれによる損害について責任を負いません。