Project: openjpeg (uclouvain/openjpeg), language: c++
Vulnerability instance: openjpeg.cve-2018-7648
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/uclouvain/openjpeg/issues/1088
## Description:
Issue: uclouvain/openjpeg#1088
Title: sprintf buffer overflow
State: closed
Created by: setharnold
Created at: 2018-02-22 01:09:33+00:00

Issue Body:
https://github.com/uclouvain/openjpeg/blob/06f7d412435ddb62f8e9935af7e306783bc4b75b/src/bin/mj2/opj_mj2_extract.c#L143

Hello, it looks like this `sprintf(3)` could overflow the buffer that is supplied for it.

Thanks


Comments:
Comment by kbabioch on 2018-03-02 13:39:24+00:00:
This is indeed a problem, when appropriate binary is built (-DBUILD_MJ2=On).

    ./build/bin/opj_mj2_extract Speedway.mj2 01234567890123456789012345678901234567890123456789                                                                                                               1 ↵
    Extracting 200 frames from file...
    =================================================================
    ==22782==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc920b6792 at pc 0x000000437008 bp 0x7ffc920b6610 sp 0x7ffc920b5da8
    WRITE of size 61 at 0x7ffc920b6792 thread T0
        #0 0x437007 in __interceptor_vsprintf /home/abuild/rpmbuild/BUILD/llvm-3.8.0.src/stage2/../projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1128:1
        #1 0x43832b in __interceptor_sprintf /home/abuild/rpmbuild/BUILD/llvm-3.8.0.src/stage2/../projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1159:1
        #2 0x4dd97a in main /home/kbabioch/openjpeg/src/bin/mj2/opj_mj2_extract.c:143:9
        #3 0x7fc128c5b724 in __libc_start_main /usr/src/debug/glibc-2.22/csu/libc-start.c:289
        #4 0x41ba68 in _start /home/abuild/rpmbuild/BUILD/glibc-2.22/csu/../sysdeps/x86_64/start.S:118

    Address 0x7ffc920b6792 is located in stack of thread T0 at offset 146 in frame
        #0 0x4dcfaf in main /home/kbabioch/openjpeg/src/bin/mj2/opj_mj2_extract.c:75

      This frame has 3 object(s):
        [32, 56) 'event_mgr'
        [96, 146) 'outfilename'
        [192, 16612) 'parameters' <== Memory access at offset 146 partially underflows this variable
    HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
          (longjmp and C++ exceptions *are* supported)
    SUMMARY: AddressSanitizer: stack-buffer-overflow /home/abuild/rpmbuild/BUILD/llvm-3.8.0.src/stage2/../projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1128:1 in __interceptor_vsprintf
    Shadow bytes around the buggy address:
      0x10001240eca0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ecb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ecc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ecd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ece0: f1 f1 f1 f1 00 00 00 f2 f2 f2 f2 f2 00 00 00 00
    =>0x10001240ecf0: 00 00[02]f2 f2 f2 f2 f2 00 00 00 00 00 00 00 00
      0x10001240ed00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ed10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ed20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ed30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x10001240ed40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    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
      Heap right redzone:      fb
      Freed heap region:       fd
      Stack left redzone:      f1
      Stack mid redzone:       f2
      Stack right redzone:     f3
      Stack partial redzone:   f4
      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
    ==22782==ABORTING


---

Comment by kbabioch on 2018-03-02 16:39:53+00:00:
This has been assigned CVE-2018-7648

---

Comment by OrenGitHub on 2018-03-08 08:18:14+00:00:
Hi @kbabioch , is it possible to publish the file Speedway.mj2 for completeness?
I'm currently working on building a one stop public shop for string CVE's and I want to have complete examples. Thanks! 

---

Comment by kbabioch on 2018-03-08 13:22:43+00:00:
Hi @OrenGitHub,

here you go: [Speedway.mj2.tar.gz](https://github.com/uclouvain/openjpeg/files/1793288/Speedway.mj2.tar.gz). Unfortunately I had to put it into an tarball, as GitHub does not support this filetype.



---

Comment by OrenGitHub on 2018-03-09 06:42:26+00:00:
Thanks, it works. I apologize for being greedy, but would it be possible to upload a file with just 1 frame instead of 200? from the CVE point of view, a minimal example is best, and the overflow occurs in the very first iteration in:

    for (snum = 0; snum < track->num_samples; snum++) {

(I've tried editing the file with bless, but can't seem to find the 200 frames number)
Thanks!!

---

Comment by kbabioch on 2018-03-11 12:26:43+00:00:
The file is really not relevant here. The buffer overflow affects the CLI parameter processing, not the image handling itself.

---

Comment by OrenGitHub on 2018-03-12 11:43:27+00:00:
I agree, but for example, if the mj2 file has incorrect format, then the buffer overflow statement might not be executed. I'm trying to synthesize the smallest *legal* mj2 file that will enable the execution of the buffer overflow statement:

    sprintf(outfilename, "%s_%05d.j2k", argv[2], snum);

---

Comment by OrenGitHub on 2018-03-12 12:25:22+00:00:
I've tried manually editing the *.mj2 file (to make it smaller but still valid) but I keep getting:

    [ERROR] MOOV box not found in file

Which means I'm somehow breaking its validity ... any advice? thanks!
I've also posted on SO, in case other users can help: https://stackoverflow.com/questions/49234803/synthesize-a-small-legal-mj2-file

---

Comment by szukw000 on 2018-03-12 16:45:51+00:00:
@setharnold, @kbabioch, @OrenGitHub,

the simplest patch follows:
```
--- openjpeg2-2018-02-16/src/bin/mj2/opj_mj2_extract.c.orig 2018-03-12 17:22:15.956095125 +0100
+++ openjpeg2-2018-02-16/src/bin/mj2/opj_mj2_extract.c  2018-03-12 17:24:26.382097168 +0100
@@ -91,6 +91,11 @@
         return 1;
     }

+    if(strlen(argv[2]) + 11 > sizeof(outfilename)) {
+        fprintf(stderr,"filename %d too long\n",strlen(argv[2]) + 10);
+        return 1;
+    }
+
     file = fopen(argv[1], "rb");

     if (!file) {
```
@OrenGitHub ,
manually editing the *.mj2 file is a very bad idea. What do you want to do with this
MJ2 file?
winfried



---

Comment by OrenGitHub on 2018-03-12 17:45:48+00:00:
I'm analyzing the openjpeg package with symbolic execution (SE).
The SE engine tests the program ( opj_mj2_extract ) by considering symbolic inputs for it.
The size of the minimal (legal) *.mj2 file is a measure for how difficult it will be for the SE engine to find
an *.mj2 file. I agree with previous posts that say that the file itself is irrelevant -- however, it does have to be a legal *.mj2 file, otherwise the sprintf statement won't be reached ...

---

Comment by setharnold on 2018-03-12 17:51:20+00:00:
The size of the minimal (legal) *.mj2 file is a measure for how difficult
it will be for the SE engine to find
an *.mj2 file. I agree with previous posts that say that the file itself is
irrelevant -- however, it does have to be a legal *.mj2 file, otherwise the
sprintf statement won't be reached ...


Oren, if you have a crashing input already that you would like to make
smaller, try the afl-tmin tool from the AFL suite of programs. It can
minimize test cases so that they still crash or still succeed, one of which
might be useful to you here. (AFL has another tool that can help annotate
the meaning behind bytes in an input file but I've never tried it on
something this complicated before, just toys. Maybe once you've got a
smaller example you might have luck with it.)

Thanks


---

Comment by szukw000 on 2018-03-13 01:09:25+00:00:
@OrenGitHub ,

do you want to test the validity of the file BEFORE calling 'opj_mj2_extract'?

Normally the validity is checked in
```
    if (mj2_read_struct(file, movie)) { /* Creating the movie structure*/
        return 1;
    }
```
which you can find in 'src/lib/openmj2/mj2.c'

Here are two tests:
```
mkdir /tmp/VERSUCH1

bin/opj_mj2_extract C_18_4K_24_FULL_CBR_CIRCLE_000.j2k /tmp/VERSUCH1/
[ERROR] Error: Expected JP Marker

bin/opj_mj2_extract openjump_jpeg2000_erdas.jp2  /tmp/VERSUCH1/
[ERROR] Unknown box in MJ2 stream
[ERROR] Unknown box in MJ2 stream
[ERROR] Unknown box in MJ2 stream
[ERROR] MOOV box not found in file
```
winfried


---

Comment by OrenGitHub on 2018-03-13 06:20:05+00:00:
@szukw000 no, I'm interested in the **smallest** *.mj2 file that **will** pass all the sanity checks from your post ... like MOOV box etc. ... 

---

Comment by szukw000 on 2018-03-13 16:06:59+00:00:
@OrenGitHub ,
the attached file is the first frame of Speedway.mj2. There is no other frame in
this file.
winfried
[first.mj2.zip](https://github.com/uclouvain/openjpeg/files/1807713/first.mj2.zip)


---

Comment by OrenGitHub on 2018-03-13 19:30:17+00:00:
Thank you very much @szukw000 !!! this is what I was looking for !!

Attachments:
https://github.com/uclouvain/openjpeg/files/1807713/first.mj2.zip
https://github.com/uclouvain/openjpeg/files/1793288/Speedway.mj2.tar.gz

Commit References:
0123456789012345678901234567890123456789
06f7d412435ddb62f8e9935af7e306783bc4b75b

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
mkdir -p build
cd build
cmake ..
make clean -s -j$(nproc)
make -j$(nproc) -s

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make cmake g++
RUN git clone https://github.com/uclouvain/openjpeg openjpeg
RUN git -C openjpeg checkout 564fbfb67830e2eb234bc16b3db8fecf54261f95
WORKDIR $SRC/openjpeg
COPY build.sh $SRC/

Additional files: