
Exploit PoC pour Snipe-IT CVE-2025-59712 et CVE-2025-59713
Ce PoC fournit un script automatisé pour exploiter CVE-2025-59712 (XSS dans l'en-tête User-Agent) et CVE-2025-59713 (désérialisation non sécurisée).
Ces deux vulnérabilités ont été découvertes par Synacktiv lors de travaux de recherche en sécurité sur le logiciel Snipe-IT. Snipe-IT est un système open-source de gestion des actifs basé sur Laravel, conçu pour aider les organisations à suivre et gérer leurs actifs physiques et numériques.
Une analyse technique est disponible dans l'avis de sécurité dédié sur le site de Synacktiv.
Ce script fournit trois sous-commandes, correspondant aux modes d'exploitation : xss, rce et fullchain.
Cette sous-commande exploite CVE-2025-59712, qui permet à un utilisateur à faibles privilèges d'injecter du JavaScript arbitraire dans la page HTML rendue lors de l'appel à la route /reports/activity. Cette action ne peut être effectuée que par un administrateur, ou un utilisateur disposant des droits de visualisation explicites pour les rapports. L'injection est possible en raison d'un assainissement incorrect du champ User-Agent lorsqu'un utilisateur met à jour ses informations de profil.
Pour ce faire, il se connecte d'abord en tant qu'utilisateur à faibles privilèges, puis injecte le code JavaScript défini dans le fichier fourni via l'option --javascript.
$ python3 exploit.py xss --help
Usage: exploit.py xss [OPTIONS]
Execute XSS attack only with custom JavaScript payload
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged username [required] │
│ * --password -p TEXT Low-privileged password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ * --javascript -js TEXT Path to custom JavaScript file [required] │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
[!IMPORTANT]
Au cours de la recherche en sécurité, les tests ont été effectués sur une version de Snipe-IT qui affichait, par défaut, le champUser-Agentdans lequel le JavaScript malveillant est injecté. Depuis le commit 10e5d88, la propriétéUser-Agentn'est plus affichée par défaut lors du rendu de la table des journaux d'actions. L'administrateur qui déclenchera le XSS doit donc avoir coché la caseUser-Agentdans les options d'affichage pour les versions de Snipe-IT postérieures à ce commit.
Cette sous-commande exploite CVE-2025-59713, qui permet une exécution de code à distance lorsque les identifiants d'un administrateur ou super-administrateur sont connus. Pour ce faire, les étapes suivantes sont effectuées :
db-dumps/mysql-snipeit.sql, qui créent un nouveau champ personnalisé et modifient le dernier journal d'action avec un objet JSON contenant la pop chain Laravel lors de la restauration.[!TIP] Par défaut, Snipe-IT inclut le fichier
.envdans la sauvegarde. Si le script le détecte, la valeur deAPP_KEYest affichée et le fichier.envest enregistré dans le répertoire./output(un emplacement personnalisé pour ce fichier peut être spécifié avec--output-dir).
[!CAUTION] Restaurer une sauvegarde déconnecte tous les utilisateurs connectés à l'instance.
/api/v1/reports/activity est appelée, ce qui déclenche la désérialisation et exécute la pop chain Laravel.$ python3 exploit.py rce --help
Usage: exploit.py rce [OPTIONS]
Execute RCE attack only (requires existing admin account)
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --admin-user -au TEXT Admin username [required] │
│ * --admin-pass -ap TEXT Admin password [required] │
│ --output-dir -od PATH Output dir for .env file [default: /home/ninja/Téléchargements/snipe-it-advisory/exploit/output] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
La sous-commande fullchain vise à chaîner les deux vulnérabilités XSS et RCE. Elle correspond à un scénario dans lequel vous n'avez accès qu'à un utilisateur à faibles privilèges et souhaitez obtenir une exécution de code à distance. Cela ne fonctionne que si l'utilisateur qui visite la page /reports/activity est un administrateur ou un super-administrateur. En effet, seuls ces rôles ont le droit de créer et de restaurer une sauvegarde, nécessaire pour empoisonner la base de données et déclencher ensuite la pop chain Laravel.
Pour ce faire, le script va :
--command, comme pour le mode RCE).User-Agent une balise <scr> pour forcer le navigateur de la victime à charger le modèle JavaScript malveillant./reports/activity, le XSS est déclenché et le JavaScript malveillant est chargé puis exécuté par le navigateur de la victime. À partir de là, les mêmes étapes que celles exécutées dans le module RCE sont effectuées, mais en JavaScript.Ce mode utilise plusieurs bibliothèques JavaScript supplémentaires ; tout le crédit revient à leurs auteurs respectifs :
$ python3 exploit.py fullchain --help
Usage: exploit.py fullchain [OPTIONS]
Execute full attack chain: XSS -> Backup manipulation -> RCE
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged user's username [required] │
│ * --password -p TEXT Low-privileged user's password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ --ip -i TEXT HTTP server IP address (default: auto-detect) │
│ * --port -P INTEGER HTTP server port [required] │
│ --admin-user -au TEXT Admin username to create [default: admin_rce] │
│ --admin-pass -ap TEXT Admin password to create [default: password123] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Pour exécuter ce script, lancez les commandes suivantes :
$ git clone https://github.com/synacktiv/CVE-2025-59712_CVE-2025-59713
$ cd CVE-2025-59712_CVE-2025-59713
$ python3 -m venv .venv && source .venv/bin/activate
$ python3 -m pip install -r requirements.txt
Un Dockerfile est également fourni afin de tester le script et de reproduire l'exploitation de la vulnérabilité. Il récupère une version vulnérable de Snipe-IT, configure la base de données avec php artisan, et met en place deux utilisateurs :
admin avec un mot de passe par défaut de AdminPassword123!lowpriv avec un mot de passe par défaut de LowPrivUser123!Avant de lancer le conteneur, les fichiers .env et snipe-it.conf doivent être mis à jour avec l'URL de l'instance Snipe-IT :
$ sed -i 's|^APP_URL=.*|APP_URL=http://<IP>:<PORT>|' .env
$ sed -i 's|\(ServerName\s*\).*|\1http://<IP>:<PORT>|' snipe-it.conf
Le conteneur peut ensuite être lancé :
$ docker build . -t "snipe-it-cve"
$ docker run -p 80:80 --name "snipe-it-debian" snipe-it-cve:latest