PhocaCart ≤ 6.1.7 — 未認証の攻撃者がチェックアウト経由で XSS ペイロードを保存。管理者ブラウザコンテキストで実行
PhocaCart 6.1.7(Joomla 用)は、store_user_agent 設定オプションが有効な場合、チェックアウトリクエストの生の HTTP User-Agent ヘッダーを注文データベーステーブルに保存します。保存された値は、Adminview.php の itemText() を介して管理者の注文編集ビューに HTML エンコードなしでレンダリングされます。
未認証の攻撃者は、JavaScript ペイロードを含む細工された User-Agent で注文を行うことができます。管理者がバックエンドで注文を開くと、ペイロードは管理者ブラウザコンテキストで実行され、セッションハイジャック、認証情報の窃取、または不正な管理操作が可能になります。
この脆弱性が成立するには、store_user_agent = 1(非デフォルト)が有効である必要があります。このオプションはブラウザ統計を収集するための管理者の意図的な選択であるため、影響を受けるショップは、ショップオーナーがこの機能を有効にしているショップです。そのため、攻撃者から見るとこの悪用は完全にサイレントです。
| コンポーネント | 影響を受けるバージョン | テスト環境 | 修正バージョン |
|---|---|---|---|
| PhocaCart (com_phocacart) | 5.0.0 – 6.1.7 | Joomla 5.4.7 + PhocaCart 6.1.7 + MariaDB 10.6 | 6.1.8 |
タイプ: 格納型 XSS(CWE-79)— 管理者を標的とした
必要な認証: 注入には不要。トリガーには管理者が必要
CSRF トークン: 必要(チェックアウトには標準の Joomla CSRF トークンが必要)
ファイル: administrator/components/com_phocacart/libraries/Phoca/Render/Adminview.php:382
store_user_agent = 1 の場合、PhocacartUtils::getUserAgent() メソッドは $_SERVER['HTTP_USER_AGENT'] をサニタイズなしで返します。この生の文字列は #__phocacart_orders に保存されます(200 文字に切り詰められますが、XSS を防ぐには不十分です)。管理者がバックエンドで注文を表示すると、itemText() は保存された値を htmlspecialchars() を呼び出さずに直接 HTML レスポンスに連結します。
データフロー:
Attacker sends checkout request:
User-Agent: <script>alert(document.domain)</script>
utils.php:334 PhocacartUtils::getUserAgent()
└─ return (string) $_SERVER['HTTP_USER_AGENT'] // raw, no sanitization
order.php:413 $d['user_agent'] = substr($user_agent, 0, 200)
└─ INSERT INTO #__phocacart_orders (user_agent) VALUES ('<script>...</script>')
Admin opens order in backend:
edit.php:84 echo $r->itemText($this->itemcommon->user_agent, ...)
Adminview.php:382 '<div class="controls >' . $item . '</div>'
// → NO htmlspecialchars()
→ Browser renders: <div><script>alert(document.domain)</script></div>
→ XSS fires in administrator's browser
ORDER.PHP — 保存フェーズ(脆弱なソース)
administrator/components/com_phocacart/libraries/phocacart/order/order.php:424
$user_agent = PhocacartUtils::getUserAgent(); // reads $_SERVER['HTTP_USER_AGENT'] raw
$d['user_agent'] = substr($user_agent, 0, 200); // stored in DB unfiltered
ADMINVIEW.PHP:382 — レンダリングフェーズ(脆弱なシンク)
// No htmlspecialchars() applied:
$output .= ' <div class="controls ' . $class . '">' . $item . '</div>' . "\n";
以下から呼び出されます administrator/components/com_phocacart/views/phocacartorder/tmpl/edit.php:84:
echo $r->itemText($this->itemcommon->user_agent, Text::_('COM_PHOCACART_USER_AGENT'), '', 'user_agent');
itemText() 関数は、$item(保存された user_agent 値)をエンコードなしで直接 HTML 出力に渡すため、主要なシンクとなります。シンクレベルで修正すれば、itemText() のすべての呼び出し元を保護できます。
この攻撃には、悪意のある User-Agent ヘッダーを使用して完全なチェックアウトフローを完了する必要があります。Joomla のチェックアウトコントローラは CSRF トークンを検証するため、まず CSRF トークンを取得する必要があります。
Joomla 管理画面で、Components → Phoca Cart → Options → Main タブ → Statistics Options に移動します。Store User Agent Information = Yes に設定して保存します。

攻撃者はショップのフロントエンドにアクセスし、チェックアウトコントローラに必要な有効な Joomla CSRF トークンを抽出します。トークンは任意のショップページの HTML ソースまたは JavaScript 設定に含まれています。

攻撃者は、無害な User-Agent を使用して AJAX チェックアウトエンドポイント経由で商品をカートに追加します。これにより、チェックアウトセッションが次の状態に遷移します。

攻撃者は請求先情報を送信し、チェックアウトのステートマシンを進めます。

攻撃者は支払いに進むため配送方法を選択します。

攻撃者は支払い方法(例: 代金引換)を選択します。

重要な注入ステップです。攻撃者は User-Agent ヘッダーを XSS ペイロードに設定し、task=checkout.order 経由で最終注文を確定します。checkout.order タスクは生の HTTP_USER_AGENT を読み取り、エスケープせずに #__phocacart_orders.user_agent に保存します。
POST /index.php/shop/checkout HTTP/1.1
Host: TARGET
User-Agent: <script>alert(document.domain)</script>
Content-Type: application/x-www-form-urlencoded
phcheckouttac=1&task=checkout.order&option=com_phocacart&return=&<CSRF_TOKEN>=1
結果: 注文が作成されます。データベースには user_agent = '<script>alert(document.domain)</script>' が保存されます。

管理者は Components → Phoca Cart → Orders に移動します。注入された注文がリストに表示されます。この段階では XSS はまだトリガーされません。

管理者が注文をクリックして編集ビューを開くと、保存された user_agent が itemText() 経由でエスケープされずにレンダリングされます。JavaScript が即座に実行されます。
トリガー URL:
/administrator/index.php?option=com_phocacart&view=phocacartorder&layout=edit&id=<ORDER_ID>
