
XSS stocké via User-Agent dans la vue des commandes de l'administration de PhocaCart
PhocaCart ≤ 6.1.7 — Un attaquant non authentifié stocke une charge utile XSS via le passage de commande. S'exécute dans le contexte du navigateur administrateur
PhocaCart 6.1.7 pour Joomla stocke l'en-tête HTTP brut User-Agent des demandes de passage de commande dans la table de la base de données des commandes lorsque l'option de configuration store_user_agent est activée. La valeur stockée est ensuite rendue sans encodage HTML dans la vue d'édition de commande administrateur via itemText() dans Adminview.php.
Un attaquant non authentifié peut passer une commande avec un conçu contenant une charge utile JavaScript. Lorsqu'un administrateur ouvre la commande dans le backend, la charge utile s'exécute dans le contexte du navigateur admin — permettant le détournement de session, le vol d'identifiants ou des actions administratives non autorisées.
User-AgentLa vulnérabilité nécessite que store_user_agent = 1 (non défaut) soit activé. Comme cette option est un choix délibéré de l'administrateur pour collecter des statistiques de navigateur, les boutiques concernées sont celles où le propriétaire de la boutique a activé la fonctionnalité — rendant l'exploitation totalement silencieuse du point de vue de l'attaquant.
| COMPOSANT | VULNÉRABLE | TESTÉ SUR | CORRIGÉ |
|---|---|---|---|
| PhocaCart (com_phocacart) | 5.0.0 – 6.1.7 | Joomla 5.4.7 + PhocaCart 6.1.7 + MariaDB 10.6 | 6.1.8 |
Type : XSS stockée (CWE-79) — ciblant l'administrateur
Authentification requise : Aucune pour injecter. Administrateur pour déclencher
Jeton CSRF requis : Oui (jeton CSRF Joomla standard requis pour le passage en caisse)
Fichier : administrator/components/com_phocacart/libraries/Phoca/Render/Adminview.php:382
Lorsque store_user_agent = 1, la méthode PhocacartUtils::getUserAgent() renvoie $_SERVER['HTTP_USER_AGENT'] sans aucune assainissement. Cette chaîne brute est stockée dans #__phocacart_orders (tronquée à 200 caractères — insuffisant pour empêcher les XSS). Lorsqu'un administrateur consulte la commande dans le backend, itemText() concatène la valeur stockée directement dans la réponse HTML sans appel à htmlspecialchars().
Flux de données :
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 — PHASE DE STOCKAGE (SOURCE VULNÉRABLE)
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 — PHASE DE RENDU (SINK VULNÉRABLE)
// No htmlspecialchars() applied:
$output .= ' <div class="controls ' . $class . '">' . $item . '</div>' . "\n";
Appelé depuis administrator/components/com_phocacart/views/phocacartorder/tmpl/edit.php:84 :
echo $r->itemText($this->itemcommon->user_agent, Text::_('COM_PHOCACART_USER_AGENT'), '', 'user_agent');
La fonction itemText() transmet $item (la valeur user_agent stockée) directement dans la sortie HTML sans encodage, ce qui en fait le sink principal. Le corriger au niveau du sink protège tous les appelants de itemText().
L'attaque nécessite d'effectuer un passage de commande complet avec un en-tête User-Agent malveillant. Le jeton CSRF doit d'abord être obtenu car le contrôleur de passage en caisse de Joomla le valide.
Dans l'administration Joomla, accédez à Composants → Phoca Cart → Options → Onglet Principal → Options de statistiques. Définissez Store User Agent Information = Oui et enregistrez.

L'attaquant visite la vitrine de la boutique pour extraire un jeton CSRF Joomla valide requis par le contrôleur de passage en caisse. Le jeton apparaît dans le code source HTML ou la configuration JavaScript de n'importe quelle page de la boutique.

L'attaquant ajoute un produit au panier via le point de terminaison AJAX de passage en caisse en utilisant un User-Agent bénin. Cela fait passer la session de passage en caisse à l'état suivant.

L'attaquant soumet les informations de facturation pour faire avancer la machine à états du passage en caisse.

L'attaquant sélectionne un mode de livraison pour passer au paiement.

L'attaquant sélectionne un mode de paiement (par exemple, paiement à la livraison).

Étape d'injection critique. L'attaquant passe la commande finale via task=checkout.order avec l'en-tête User-Agent défini sur la charge utile XSS. La tâche checkout.order lit le HTTP_USER_AGENT brut et le stocke sans échappement dans #__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
Résultat : commande créée. La base de données stocke user_agent = '<script>alert(document.domain)</script>'.

L'administrateur accède à Composants → Phoca Cart → Commandes. La commande injectée apparaît dans la liste. Le XSS n'est pas encore déclenché à ce stade.

Lorsque l'administrateur clique sur la commande pour ouvrir la vue d'édition, le user_agent stocké est rendu sans échappement via itemText(). JavaScript s'exécute immédiatement.
URL de déclenchement :
/administrator/index.php?option=com_phocacart&view=phocacartorder&layout=edit&id=<ORDER_ID>
