
XSS Armazenado via User-Agent na Visualização de Pedidos do Admin no PhocaCart
PhocaCart ≤ 6.1.7 — Atacante não autenticado armazena payload de XSS via checkout. Executa no contexto do navegador do administrador
O PhocaCart 6.1.7 para Joomla armazena o cabeçalho HTTP User-Agent bruto das solicitações de checkout na tabela de pedidos do banco de dados quando a opção de configuração store_user_agent está habilitada. O valor armazenado é posteriormente renderizado sem codificação HTML na visualização de edição de pedido do administrador via itemText() em Adminview.php.
Um atacante não autenticado pode fazer um pedido com um adulterado contendo um payload de JavaScript. Quando um administrador abre o pedido no backend, o payload é executado no contexto do navegador do administrador — permitindo sequestro de sessão, roubo de credenciais ou ações administrativas não autorizadas.
User-AgentA vulnerabilidade exige que store_user_agent = 1 (não padrão) esteja habilitado. Como essa opção é uma escolha deliberada do administrador para coletar estatísticas de navegador, as lojas afetadas são aquelas em que o proprietário habilitou o recurso — tornando a exploração totalmente silenciosa do ponto de vista do atacante.
| COMPONENTE | VULNERÁVEL | TESTADO EM | CORRIGIDO |
|---|---|---|---|
| PhocaCart (com_phocacart) | 5.0.0 – 6.1.7 | Joomla 5.4.7 + PhocaCart 6.1.7 + MariaDB 10.6 | 6.1.8 |
Tipo: XSS armazenado (CWE-79) — direcionado ao administrador
Autenticação necessária: Nenhuma para injetar. Administrador para acionar
Token CSRF necessário: Sim (token CSRF padrão do Joomla obrigatório para o checkout)
Arquivo: administrator/components/com_phocacart/libraries/Phoca/Render/Adminview.php:382
Quando store_user_agent = 1, o método PhocacartUtils::getUserAgent() retorna $_SERVER['HTTP_USER_AGENT'] sem nenhuma sanitização. Essa string bruta é armazenada em #__phocacart_orders (truncada em 200 caracteres — insuficiente para evitar XSS). Quando um administrador visualiza o pedido no backend, itemText() concatena o valor armazenado diretamente na resposta HTML sem nenhuma chamada a htmlspecialchars().
Fluxo de dados:
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 — FASE DE ARMAZENAMENTO (ORIGEM VULNERÁVEL)
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 — FASE DE RENDERIZAÇÃO (SINK VULNERÁVEL)
// No htmlspecialchars() applied:
$output .= ' <div class="controls ' . $class . '">' . $item . '</div>' . "\n";
Chamado por administrator/components/com_phocacart/views/phocacartorder/tmpl/edit.php:84:
echo $r->itemText($this->itemcommon->user_agent, Text::_('COM_PHOCACART_USER_AGENT'), '', 'user_agent');
A função itemText() passa $item (o valor user_agent armazenado) diretamente para a saída HTML sem nenhuma codificação, tornando-a o principal sink. Corrigir isso no nível do sink protege todos os chamadores de itemText().
A exploração exige concluir um fluxo de checkout completo com um cabeçalho User-Agent malicioso. O token CSRF deve ser obtido primeiro, pois o controlador de checkout do Joomla o valida.
No admin do Joomla, navegue até Componentes → Phoca Cart → Opções → Guia Principal → Opções de Estatísticas. Defina Armazenar Informações do User-Agent = Sim e salve.

O atacante visita o frontend da loja para extrair um token CSRF válido do Joomla, necessário para o controlador de checkout. O token aparece no HTML ou na configuração JavaScript de qualquer página da loja.

O atacante adiciona um produto ao carrinho por meio do endpoint AJAX de checkout usando um User-Agent benigno. Isso faz a sessão de checkout avançar para o próximo estado.

O atacante envia as informações de cobrança para avançar a máquina de estados do checkout.

O atacante seleciona um método de envio para prosseguir para o pagamento.

O atacante seleciona um método de pagamento (ex.: Pagamento na Entrega).

Etapa crítica de injeção. O atacante faz o pedido final via task=checkout.order com o cabeçalho User-Agent definido para o payload de XSS. A tarefa checkout.order lê o HTTP_USER_AGENT bruto e o armazena sem escape em #__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
Resultado: pedido criado. O banco de dados armazena user_agent = '<script>alert(document.domain)</script>'.

O administrador navega até Componentes → Phoca Cart → Pedidos. O pedido injetado aparece na lista. O XSS ainda não é acionado nesta etapa.

Quando o administrador clica no pedido para abrir a visualização de edição, o user_agent armazenado é renderizado sem escape via itemText(). O JavaScript é executado imediatamente.
URL de acionamento:
/administrator/index.php?option=com_phocacart&view=phocacartorder&layout=edit&id=<ORDER_ID>
