Project: exiv2 (exiv2/exiv2), language: c++
Vulnerability instance: exiv2.cve-2017-17725
Sanitizer: address

================= Bug Report (1/2) ==================
## Source: Red Hat Bugzilla
## URL: https://bugzilla.redhat.com/show_bug.cgi?id=1525055
## Description:
Bugzilla ID: 1525055
Title: exiv2 library: heap-buffer-overflow in Exiv2::getULong (types.cpp)

Description
Wei You 2017-12-12 14:36:13 UTC
Created attachment 1366691 [details]
poc to trigger the vulnerability

Description

on exiv2 0.26 (the latest version):

there is a heap-based buffer overflow in the Exiv2::getULong function (src/types.cpp), which can be triggered by crafted tiff file.

Note that this vulnerability is different from CVE-2017-14864, which is a an invalid memory address dereference.

./bin/exiv2 poc_3.tiff

=================================================================
==16413==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000ef73 at pc 0x7f990f1613de bp 0x7ffee8097c30 sp 0x7ffee8097c20
READ of size 4 at 0x60200000ef73 thread T0
#0 0x7f990f1613dd in Exiv2::getULong(unsigned char const*, Exiv2::ByteOrder) /home/fuzz/exiv2/master/src/types.cpp:246
#1 0x7f990f053d2c in Exiv2::Jp2Image::readMetadata() /home/fuzz/exiv2/master/src/jp2image.cpp:271
#2 0x469742 in Action::Print::printSummary() /home/fuzz/exiv2/master/src/actions.cpp:288
#3 0x46e2e7 in Action::Print::run(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) /home/fuzz/exiv2/master/src/actions.cpp:240
#4 0x40c18b in main /home/fuzz/exiv2/master/src/exiv2.cpp:166
#5 0x7f990e33d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#6 0x40cd48 in _start (/home/fuzz/exiv2/master/bin/exiv2+0x40cd48)

0x60200000ef75 is located 0 bytes to the right of 5-byte region [0x60200000ef70,0x60200000ef75)
allocated by thread T0 here:
#0 0x7f990faed6b2 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x996b2)
#1 0x7f990f053c49 in Exiv2::DataBuf::DataBuf(long) /home/fuzz/exiv2/master/include/exiv2/types.hpp:206
#2 0x7f990f053c49 in Exiv2::Jp2Image::readMetadata() /home/fuzz/exiv2/master/src/jp2image.cpp:269

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/fuzz/exiv2/master/src/types.cpp:246 Exiv2::getULong(unsigned char const*, Exiv2::ByteOrder)
Shadow bytes around the buggy address:
0x0c047fff9d90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[05]fa
0x0c047fff9df0: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa fd fd
0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e30: 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
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
==16413==ABORTING

Reference:
https://github.com/Exiv2/exiv2/issues/188

Author
Credit to Wei You, please contact WeiYou1988 for more details.


Comments:
Comment 2
Wei You 2017-12-12 20:19:55 UTC
Created attachment 1366916 [details]
poc_2018-12-12_issue188

---

Comment 4
Jan Grulich 2019-01-28 16:08:30 UTC
Fixed with exiv2-0.27.0-1.el7_6.

---

Comment 8
errata-xmlrpc 2019-08-06 12:47:14 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHSA-2019:2101

Attachments:
Attachment 1366691: poc to trigger the vulnerability [Link: https://bugzilla.redhat.com/attachment.cgi?id=1366691]
Attachment 1366916: poc_2018-12-12_issue188 [Link: https://bugzilla.redhat.com/attachment.cgi?id=1366916]

================= Bug Report (2/2) ==================
## Source: GitHub Issue
## URL: https://github.com/Exiv2/exiv2/issues/188
## Description:
Issue: Exiv2/exiv2#188
Title: CVE-2017-17725: exiv2 library: heap-buffer-overflow in Exiv2::getULong (types.cpp)
State: closed
Created by: youwei1988
Created at: 2017-12-12 14:27:30+00:00

Issue Body:
**Description**

on exiv2 0.26 (the latest version):

there is a heap-based buffer overflow in the Exiv2::getULong function (src/types.cpp), which can be triggered by crafted tiff file. 

Note that this vulnerability is different from CVE-2017-14864 (issue 73), which is a an invalid memory address dereference.

./bin/exiv2 poc_3.tiff

=================================================================
==16413==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000ef73 at pc 0x7f990f1613de bp 0x7ffee8097c30 sp 0x7ffee8097c20
READ of size 4 at 0x60200000ef73 thread T0
    #0 0x7f990f1613dd in Exiv2::getULong(unsigned char const*, Exiv2::ByteOrder) /home/fuzz/exiv2/master/src/types.cpp:246
    #1 0x7f990f053d2c in Exiv2::Jp2Image::readMetadata() /home/fuzz/exiv2/master/src/jp2image.cpp:271
    #2 0x469742 in Action::Print::printSummary() /home/fuzz/exiv2/master/src/actions.cpp:288
    #3 0x46e2e7 in Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/fuzz/exiv2/master/src/actions.cpp:240
    #4 0x40c18b in main /home/fuzz/exiv2/master/src/exiv2.cpp:166
    #5 0x7f990e33d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #6 0x40cd48 in _start (/home/fuzz/exiv2/master/bin/exiv2+0x40cd48)

0x60200000ef75 is located 0 bytes to the right of 5-byte region [0x60200000ef70,0x60200000ef75)
allocated by thread T0 here:
    #0 0x7f990faed6b2 in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x996b2)
    #1 0x7f990f053c49 in Exiv2::DataBuf::DataBuf(long) /home/fuzz/exiv2/master/include/exiv2/types.hpp:206
    #2 0x7f990f053c49 in Exiv2::Jp2Image::readMetadata() /home/fuzz/exiv2/master/src/jp2image.cpp:269

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/fuzz/exiv2/master/src/types.cpp:246 Exiv2::getULong(unsigned char const*, Exiv2::ByteOrder)
Shadow bytes around the buggy address:
  0x0c047fff9d90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[05]fa
  0x0c047fff9df0: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa fd fd
  0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e30: 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
  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
==16413==ABORTING


**PoC**
PoC: https://github.com/youwei1988/poc/tree/master/exiv2/poc_3.tiff


**Author**
Credit to Wei You, please contact WeiYou1988@gmail.com for more details.



Comments:
Comment by D4N on 2017-12-12 14:50:17+00:00:
Thanks for your report. With which version of exiv2 did you try this? The `v0.26` git tag, the head of the `0.26` branch or the head of `master` (or something else)?

---

Comment by youwei1988 on 2017-12-12 14:54:27+00:00:
@D4N Thanks for reply. 
I tried both v0.26 git tag and the branch of head of master, they are both affected. I will try more versions later.

---

Comment by clanmills on 2017-12-12 16:44:42+00:00:
I'm working on 'master' and unable to reproduced this on Linux/MacOS/Cygwin.  Here's my result:
```
575 rmills@rmillsmm-w7:~/gnu/github/exiv2/exiv2 $ exiv2 poc_3.tiff
Exiv2 exception in print action for file poc_3.tiff:
corrupted image metadata
576 rmills@rmillsmm-w7:~/gnu/github/exiv2/exiv2 $
```
I'm not going to close this issue as it deserves more investigation.  I'm currently working on long-term maintenance of our msvc/ and autotools/ and buildserver support.  I will add the file poc_3.tiff to our test suite to ensure that this issue does not regress.

May I ask you to name give the "poc" files more meaningful/unique names that we can track.  For example, add the date (in iso format). poc_2018-12-12 

---

Comment by youwei1988 on 2017-12-12 20:26:22+00:00:
@clanmills 

Thank you very much for your testing.
I have git pull the latest version of the 'master' and still got the heap-buffer-overflow error.

Did you build exiv2 with Address Sanitizer?
Like: CC=gcc CXX=g++ CFLAGS="-fsanitize=address" CXXFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address"  cmake . && make

Also, I have named the poc with poc_2018-12-12_issue188. 
Here is the link: https://github.com/youwei1988/poc/blob/master/exiv2/poc_2018-12-12_issue188

Note: please do not use wget to get the file from the URL directly, it will not be the one I uploaded, which will cause the result "Exiv2 exception in print action for file...". Please click the link and press the download button to get the file I submitted in the github.

For your convenience, I also uploaded the poc to https://bugzilla.redhat.com/attachment.cgi?id=1366916, which can be get directly by using wget. 

Thanks again.

---

Comment by clanmills on 2017-12-12 23:02:00+00:00:
Thanks @youwei1988.  I will investigate all your concerns.  And thank you for using my file-date suggestion.  As I said: _this issue as it deserves more investigation_  I'll build the code as you've suggested.

---

Comment by piponazo on 2017-12-14 20:39:33+00:00:
Hi, I could reproduce the issue in my Linux box:

- Xubuntu 17.04
- Gcc 7.2

I would be happy to work on this issue :)

---

Comment by clanmills on 2017-12-14 21:51:19+00:00:
@piponazo Happy to accept your offer.  I wonder why you've reproduced this and I have not.  Puzzling.  I'm using the latest MacOS-X + clang.  Ubuntu 16.04LTS + GCC 5.something.

---

Comment by piponazo on 2017-12-14 21:55:21+00:00:
Did you try to do what @youwei1988 suggested ? These are the exact steps I did to reproduce the issue:

```
rm -rf build
mkdir build && cd build
conan install ..
CFLAGS="-fsanitize=address" CXXFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" cmake .. && make -j4
# run the command
```

---

Comment by piponazo on 2017-12-14 21:56:09+00:00:
Note that if you use **clang** instead of **gcc** you might need to use other flags. I have been a long time without playing with sanitizers.

---

Comment by piponazo on 2017-12-14 22:27:59+00:00:
I have been debugging the code and I think I have detected where is the issue.

In the file **jp2image.cpp** line 254 we are reading the Jp2BoxHeader "subBoxes". After reading some subboxes we reach a case where its lenght is **4294967293**. Then in lines 270 and 271 we hit the issue.

I am not very sure about how to fix the issue. @D4N maybe you can give me some hints about how to fix these issues since you have been fixing many of them lately ;)

---

Comment by piponazo on 2017-12-14 22:59:46+00:00:
This is the output that I get  (after adding the DEBUG compiler definition: #192 ):

```
(conan) ✔ /media/linuxDev/programming/exiv2/build [bug188 L|✚ 2…1⚑ 1] 
23:57 $ bin/exiv2 ../poc_2018-12-12_issue188 
Exiv2::Jp2Image::readMetadata: Reading JPEG-2000 file ../poc_2018-12-12_issue188
Exiv2::Jp2Image::readMetadata: Position: 20 box type: jp2h length: 20
Exiv2::Jp2Image::readMetadata: JP2Header box found
Exiv2::Jp2Image::readMetadata: subBox = �� length = 1785737760
Exiv2::Jp2Image::readMetadata: Position: 40 box type: jp2h length: 45
Exiv2::Jp2Image::readMetadata: JP2Header box found
Exiv2::Jp2Image::readMetadata: subBox = ihdr length = 22
Exiv2::Jp2Image::readMetadata: Ihdr data found
Exiv2::Jp2Image::readMetadata: subBox = colr length = 4294967293
Exiv2::Jp2Image::readMetadata: Color data found
=================================================================
==27597==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000002d5 at pc 0x7f66b46405fc bp 0x7fffbffbfb70 sp 0x7fffbffbfb60
READ of size 1 at 0x6020000002d5 thread T0
    #0 0x7f66b46405fb in Exiv2::getULong(unsigned char const*, Exiv2::ByteOrder) /media/linuxDev/programming/exiv2/src/types.cpp:246
    #1 0x7f66b45c00fd in Exiv2::Jp2Image::readMetadata() /media/linuxDev/programming/exiv2/src/jp2image.cpp:276
    #2 0x56233be5d018 in Action::Print::printSummary() /media/linuxDev/programming/exiv2/src/actions.cpp:288
    #3 0x56233be5be10 in Action::Print::run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /media/linuxDev/programming/exiv2/src/actions.cpp:240
    #4 0x56233be3bc87 in main /media/linuxDev/programming/exiv2/src/exiv2.cpp:166
    #5 0x7f66b38ad1c0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x211c0)
    #6 0x56233be3b509 in _start (/media/linuxDev/programming/exiv2/build/bin/exiv2+0x2c509)
...
```

---

Comment by D4N on 2017-12-14 23:21:11+00:00:
The problem is two-fold:
1. an integer overflows: `subBox.length` is a `uint32_t` whose largest value is 4294967295, `subBox.length` is 4294967293. So once you add more than 2 to it, the whole thing overflows, which happens in line 269 of jp2image.cpp.
2. `subBox.length` is used to create a new `DataBuf`, but due to the overflow it has only a size of 5. However the invocation in line 271 wants to extract 4 bytes from the `DataBuf` `data` at an offset of `pad` (which is `3`) so that creates an out of bounds read, which ASAN catches.

I think there are two things that should be done here:
1. make sure that the addition in line 269 does not overflow
2. verify that `subBox.length` is not out of bounds of the image file, if that makes sense (I have no clue what jpeg subboxes are)

---

Comment by clanmills on 2017-12-15 12:12:13+00:00:
I can't remember what a box is either - something in the architecture on the JPEG2000 file format.

This is very good work indeed, @D4N.  Thanks you very much.

May I say something concerning 32bit vs 64bit?  There's an overflow detect in tiff visitor_int.cpp about line 1523 that's based on uintptr_t.  It's working OK in 64 bits, and not in 32 bits (on MSVC for sure, I haven't tested other platforms).  Do you think it's possible to move the overflow detector into a utility function which we can call from different locations.  By having the detector in a single function, we can "tune" it for 32/64 bit builds.

Gentlemen (@D4N and @piponazo)  Thank You very much indeed for all your hard work.  Believe me, it is appreciated.

---

Comment by D4N on 2017-12-15 14:06:21+00:00:
Coincidentally, I have started just started working on such an overflow detector on Wednesday. I'll make an issue/PR about it soon, since there are some details to discuss about it (especially concerning how we are going to handle failures).

---

Comment by D4N on 2018-01-05 22:48:08+00:00:
I think we can close this, or is there anything left to do?

---

Comment by youwei1988 on 2018-01-06 13:15:31+00:00:
I have tested the latest version and found this vulnerability has been fixed. Thanks for all your work.

---

Comment by ghost on 2018-02-13 08:36:16+00:00:
This has been assigned CVE-2017-17725

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
mkdir -p build
cd build
cmake -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=OFF -DEXIV2_ENABLE_BMFF=ON -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_CXX_COMPILER="${CXX}" -DCMAKE_CXX_FLAGS="${CXXFLAGS}" -DEXIV2_BUILD_FUZZ_TESTS=ON -DEXIV2_TEAM_OSS_FUZZ=ON -DLIB_FUZZING_ENGINE="${LIB_FUZZING_ENGINE}" ..
make -j $(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y cmake make ccache python3 libexpat1-dev zlib1g-dev libssh-dev libcurl4-openssl-dev libxml2-utils
RUN git clone https://github.com/exiv2/exiv2 exiv2
RUN git -C exiv2 checkout fa449a4d2c58d63f0d75ff259f25683a98a44630
WORKDIR $SRC/exiv2
COPY build.sh $SRC/

Additional files: