Reports
MEDIA[DENEGACIÓN DE SERVICIO]#3872239

MariaDB Connector/J: un servidor malicioso tumba la JVM del cliente con un número de columnas desorbitado

El driver JDBC de MariaDB reservaba un array del tamaño que dictaba el servidor. Un servidor hostil o un atacante en la red podía provocar un OutOfMemoryError y hundir toda la aplicación Java.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

MariaDB Connector/J, el driver JDBC de MariaDB, confiaba ciegamente en un dato que llega del servidor: el número de columnas de un resultado. Ese valor se lee de la conexión como entero de longitud codificada y se usa tal cual para crear un array en Java, sin comprobar ningún límite. Es un fallo de consumo de recursos sin control (CWE-400).

El código afectado está en src/main/java/org/mariadb/jdbc/message/ClientMessage.java:

default:
    int fieldCount = buf.readIntLengthEncodedNotNull();   // line 282: server-controlled
    ColumnDecoder[] ci;
    if (context.canSkipMeta() && this.canSkipMeta()) {
      ...
    } else {
      ci = new ColumnDecoder[fieldCount];                 // line 302: unbounded allocation
      for (int i = 0; i < fieldCount; i++) { ... }
    }

La función readIntLengthEncodedNotNull() (ReadableByteBuf.java:148) devuelve el valor recibido sin tocarlo; en la forma 0xfe hace return (int) readLong(), así que quien controle la respuesta decide el entero de 32 bits completo. Según el valor elegido, el resultado cambia:

  • fieldCount = 0x10000000 (unos 268 millones): OutOfMemoryError: Java heap space
  • fieldCount = 0x7fffffff: OutOfMemoryError: Requested array size exceeds VM limit
  • fieldCount = 0xffffffff: NegativeArraySizeException

Ninguna de estas excepciones se captura dentro de readPacket. Basta un paquete de unos 10 bytes.

Un detalle agrava el problema: por defecto el driver usa sslMode=DISABLE (Configuration.java:309), es decir, tráfico en claro. No hace falta controlar la base de datos real; un atacante situado en la red entre cliente y servidor puede reescribir la respuesta.

El investigador señaló además otros puntos de la misma familia: Reader.java:133 (un acumulador sin límite) y OkPacket.java:160 (new byte[readIntLengthEncodedNotNull()]), y citó como precedente el reporte #3835450, un fallo equivalente aceptado en connector-nodejs con severidad media.

Pasos de reproducción

Entorno de la prueba: OpenJDK 21 y el driver compilado desde el commit c9377bc (mariadb-java-client-3.5.9.jar). El investigador adjuntó rogue_server.py, OomClient.java, run_poc.sh y poc_evidence.txt.

  1. Arrancar el servidor falso. Completa el saludo inicial en texto plano, responde OK a la consulta de configuración que lanza el driver y, cuando recibe SELECT 1, contesta con una cabecera de resultado que declara fieldCount = 0x10000000:
python3 rogue_server.py positive 0 &
  1. Lanzar un cliente JDBC corriente contra ese servidor, con el heap limitado a 256 MB:
java -Xmx256m -cp .:mariadb-java-client-3.5.9.jar OomClient "jdbc:mariadb://127.0.0.1:<port>/test?user=app&password=[REDACTADO]"

La JVM muere al intentar reservar el array:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:302)
        at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1438)
        at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1377)
        at org.mariadb.jdbc.Statement.executeQuery(Statement.java:137)
        at OomClient.main(OomClient.java:22)
client exit code = 1
  1. Variante en la conexión: con el servidor en modo connect, la respuesta manipulada se inyecta en la propia consulta de configuración del driver. El fallo salta dentro de DriverManager.getConnection(), antes de que la aplicación ejecute nada y sin necesidad de credenciales válidas:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:302)
        at org.mariadb.jdbc.client.impl.StandardClient.postConnectionQueries(StandardClient.java:816)
        at org.mariadb.jdbc.Driver.connect(Driver.java:75)
  1. Control negativo: mismo driver, misma URL y mismo SELECT 1, pero con una respuesta legítima de una columna. Todo funciona:
connected; running SELECT 1
RESULT=1
CLEAN_EXIT
client exit code = 0

Lo único que cambia entre ambos casos es el número de columnas que anuncia el servidor.

Impacto

Con un solo paquete pequeño, un servidor malicioso o un intermediario en la red hace caer la JVM del cliente. Un OutOfMemoryError no afecta solo a una consulta: tumba la aplicación entera, con todas las conexiones del pool y todos los hilos de trabajo.

Como la variante de conexión se dispara dentro de DriverManager.getConnection(), no hacen falta credenciales válidas ni consultas de la aplicación. Cualquier servicio que abra una conexión JDBC hacia un destino en el que el atacante pueda influir queda expuesto: cadenas de conexión controlables al estilo SSRF, un MITM sobre un enlace sin cifrar, un servidor de base de datos comprometido o una réplica hostil en una topología con conmutación por error.

La única condición es que el atacante controle los bytes que recibe el cliente; con el sslMode=DISABLE por defecto, basta con estar en la red.

El reporte se envió el 18 de julio de 2026, quedó resuelto con severidad media y se hizo público el 30 de septiembre de 2026.