PhocaCart ≤ 6.1.7 — 未认证攻击者通过结账流程存储 XSS 载荷,并在管理员浏览器上下文中执行
当启用 store_user_agent 配置选项时,用于 Joomla 的 PhocaCart 6.1.7 会将结账请求中的原始 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() 会将存储的值直接拼接到 HTML 响应中,且未调用 htmlspecialchars()。
数据流:
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 令牌,因此必须先获取该令牌。
在 Joomla 管理后台中,导航至 组件 → Phoca Cart → 选项 → 主选项卡 → 统计选项。将 存储用户代理信息 设置为 是 并保存。

攻击者访问商店前台,提取结账控制器所需的有效 Joomla CSRF 令牌。该令牌出现在任意商店页面的 HTML 源码或 JavaScript 配置中。

攻击者通过 AJAX 结账端点,使用正常的 User-Agent 将商品加入购物车。这会将结账会话推进到下一状态。

攻击者提交账单信息以推进结账状态机。

攻击者选择配送方式以进入支付环节。

攻击者选择支付方式(例如货到付款)。

关键注入步骤。攻击者通过 task=checkout.order 提交最终订单,并将 User-Agent 标头设置为 XSS 载荷。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>'。

管理员导航至 组件 → Phoca Cart → 订单。注入的订单出现在列表中。此阶段尚未触发 XSS。

当管理员点击订单打开编辑视图时,存储的 user_agent 通过 itemText() 未转义地渲染出来。JavaScript 立即执行。
触发 URL:
/administrator/index.php?option=com_phocacart&view=phocacartorder&layout=edit&id=<ORDER_ID>
