TLS ECH Transcript Heap Buffer Overflow
## Summary This was for me quite a complex one to reproduce properly and understand, so I hope it's clear. packet-tls-utils.c contains a heap buffer overflow in the code that reconstructs the ClientHelloInner transcript after decrypting an Encrypted Client Hello (ECH). The buffer is allocated based on the outer ClientHello size, but the transcript is populated using fields from the inner ClientHello (cipher suites, compression, inner-only extensions) which can be arbitrarily larger. No bounds checking is performed on any of the writes. Trying with more details. ``` When Wireshark decrypts a TLS ClientHello with Encrypted Client Hello (ECH), it reconstructs the "ClientHelloInner" transcript by: 1. Allocating a buffer sized to: hello_length + 4 (where hello_length = the OUTER ClientHello body size) 2. Copying fixed fields: - Handshake header (4 bytes) - Version + Random from inner (34 bytes) - Session ID from OUTER - Cipher suites from INNER ← key: uses INNER size - Compression from INNER 3. For each extension in the inner ClientHello: - If regular: copy from inner (bounded by inner size) - If ECH_OUTER_EXTENSIONS: expand by copying referenced outer exts The buffer is sized for the OUTER ClientHello. But the transcript uses the INNER cipher suite list (which can be much larger than outer's) and the INNER's own extensions (which the outer doesn't have). Overflow condition (simplified): inner_cs_len - outer_cs_len + inner_own_exts - unreferenced_outer_exts > 0 Example: Outer CH: 2-byte cipher suite list, 260 bytes of extensions (200-byte supported_groups + 54-byte ECH extension) Inner CH: 500-byte cipher suite list, extensions: - ECH_OUTER_EXTENSIONS referencing supported_groups (7 bytes compressed) - server_name extension with 300-byte hostname (inner only, 304 bytes) Buffer = outer body + 4 = 337 bytes Transcript = 4 + 34 + 33 + 502 + 2 + 2 + 204 + 304 = 1085 bytes OVERFLOW: 748 bytes past allocation ``` Affected code: epan/dissectors/packet-tls-utils.c, lines 10059–10114 Wireshark 4.7.0 (HEAD: db3e7964fd) — March 30, 2026 ## AI assistance After crash found for analysis ## Sample capture file No pcap in this case. I did a test_ech_overflow.c if you need to reproduce. ## Steps to reproduce 1. Wireshark must successfully decrypt the ECH payload (requires the ECH private key configured in TLS settings) 2. The decrypted inner ClientHello must have larger cipher suites or additional extensions compared to the outer ClientHello 3. Opening a pcap or live-capturing TLS traffic where these conditions are met This is triggered during passive dissection — no special user action beyond having the ECH key configured. ## What is the current bug behavior? ``` ================================================================= ==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x513000000351 at pc 0xffffb85c5124 bp 0xffffd4322460 sp 0xffffd4321c40 WRITE of size 502 at 0x513000000351 thread T0 #0 0xffffb85c5120 in memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115 #1 0xaaaabf632434 in main /poc/test_ech_overflow.c:290 #2 0xffffb83484c0 (/lib/aarch64-linux-gnu/libc.so.6+0x284c0) (BuildId: d5ef86dde36cbd3289566cf5098226035d76f2e1) #3 0xffffb8348594 in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x28594) (BuildId: d5ef86dde36cbd3289566cf5098226035d76f2e1) #4 0xaaaabf63116c in _start (/poc/test_ech+0x116c) (BuildId: f868e09f3127ddf9d8c6eb84a4cf69c59ff88abf) 0x513000000351 is located 0 bytes after 337-byte region [0x513000000200,0x513000000351) allocated by thread T0 here: #0 0xffffb85c76d0 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69 #1 0xaaaabf632160 in main /poc/test_ech_overflow.c:246 #2 0xffffb83484c0 (/lib/aarch64-linux-gnu/libc.so.6+0x284c0) (BuildId: d5ef86dde36cbd3289566cf5098226035d76f2e1) #3 0xffffb8348594 in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x28594) (BuildId: d5ef86dde36cbd3289566cf5098226035d76f2e1) #4 0xaaaabf63116c in _start (/poc/test_ech+0x116c) (BuildId: f868e09f3127ddf9d8c6eb84a4cf69c59ff88abf) SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115 in memcpy Shadow bytes around the buggy address: 0x513000000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x513000000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x513000000180: 00 05 fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x513000000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x513000000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x513000000300: 00 00 00 00 00 00 00 00 00 00[01]fa fa fa fa fa 0x513000000380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x513000000400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x513000000480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x513000000500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x513000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==1==ABORTING ``` ## What is the expected correct behavior? (What you should see instead) ## Build information ``` TShark (Wireshark) 4.7.0 (v4.7.0rc0-2370-g8452a734cefb). Copyright 1998-2026 Gerald Combs <gerald@wireshark.org> and contributors. Licensed under the terms of the GNU General Public License (version 2 or later). This is free software; see the file named COPYING in the distribution. There is NO WARRANTY; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compile-time info: Bit width: 64-bit Compiler: GCC 13.3.0 GLib: 2.80.0 With: +Gcrypt 1.10.3 +libxml2 2.9.14 +zlib 1.3 +libpcap +PCRE2 10.42 2022-12-11 Without: -brotli -Lua -POSIX capabilities -GnuTLS -LZ4 -Snappy -Kerberos -MaxMind -xxhash -libnl -nghttp2 -zlib-ng -libsmi -nghttp3 -Zstandard Runtime info: OS: Linux 6.12.76-linuxkit CPU: Memory: 7835 MB of physical memory GLib: 2.80.0 Locale: LC_TYPE=C Plugins: supported, 0 loaded With: +c-ares 1.27.0 +PCRE2 10.42 2022-12-11 +Gcrypt 1.10.3 +zlib 1.3 +libpcap 1.10.4 (with TPACKET_V3) ```
issue