Headline
CVE-2023-40968: Detected Crash: AddressSanitizer: heap-buffer-overflow · Issue #115 · hzeller/timg
Buffer Overflow vulnerability in hzeller timg v.1.5.2 and before allows a remote attacker to cause a denial of service via the 0x61200000045c address.
I use afl++ fuzzing this program
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
cmake -B build && cmake --build build
➜ src ./timg --version
timg 1.5.1+ <https://timg.sh/>
Copyright (c) 2016..2023 Henner Zeller. This program is free software; license GPL 2.0.
Image decoding GraphicsMagick 1.3.38 (2022-03-26)
Turbo JPEG
QOI Image reader
STB image loading fallback
Video decoding libav 58.76.100
Half, quarter, iterm2, and kitty encoding timg builtin.
Libsixel version 1.8.6
then build afl++ run this poc
=================================================================
==2368346==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61200000045c at pc 0x00000051d18e bp 0x7fff288903e0 sp 0x7fff288903d8
WRITE of size 4 at 0x61200000045c thread T0
#0 0x51d18d in void timg::StoreBacking<2>(timg::rgba_t*, timg::rgba_t const*, timg::rgba_t const*) /home/xxx/timg-1.5.1/src/unicode-block-canvas.cc:145:20
#1 0x51d18d in char* timg::UnicodeBlockCanvas::AppendDoubleRow<2, 24>(char*, int, int, timg::rgba_t const*, timg::rgba_t const*, bool, int*) /home/xxx/timg-1.5.1/src/unicode-block-canvas.cc:305:9
#2 0x518011 in timg::UnicodeBlockCanvas::Send(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration) /home/xxx/timg-1.5.1/src/unicode-block-canvas.cc:374:23
#3 0x5126c6 in timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)::operator()(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&) const /home/xxx/timg-1.5.1/src/renderer.cc:50:22
#4 0x5126c6 in void std::__invoke_impl<void, timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration>(std::__invoke_other, timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int&&, int&&, timg::Framebuffer const&, timg::SeqType&&, timg::Duration&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:61:14
#5 0x5126c6 in std::enable_if<__and_<std::is_void<void>, std::__is_invocable<timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration> >::value, void>::type std::__invoke_r<void, timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration>(timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int&&, int&&, timg::Framebuffer const&, timg::SeqType&&, timg::Duration&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:154:7
#6 0x5126c6 in std::_Function_handler<void (int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration), timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)>::_M_invoke(std::_Any_data const&, int&&, int&&, timg::Framebuffer const&, timg::SeqType&&, timg::Duration&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_function.h:290:9
#7 0x5730d7 in std::function<void (int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration)>::operator()(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration) const /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_function.h:590:9
#8 0x5730d7 in timg::STBImageSource::SendFrames(timg::Duration const&, int, int const volatile&, std::function<void (int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration)> const&) /home/xxx/timg-1.5.1/src/stb-image-source.cc:163:13
#9 0x4e10eb in PresentImages(std::vector<std::future<timg::ImageSource*>, std::allocator<std::future<timg::ImageSource*> > >*, timg::DisplayOptions const&, timg::PresentationOptions const&, timg::BufferedWriteSequencer*, bool*) /home/xxx/timg-1.5.1/src/timg.cc:373:17
#10 0x4e10eb in main /home/xxx/timg-1.5.1/src/timg.cc:960:5
#11 0x7fa43c829d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#12 0x7fa43c829e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#13 0x426ee4 in _start (/home/xxx/timg-1.5.1/afl/src/timg+0x426ee4)
0x61200000045c is located 0 bytes to the right of 284-byte region [0x612000000340,0x61200000045c)
allocated by thread T0 here:
#0 0x4a40c3 in __interceptor_realloc (/home/xxx/timg-1.5.1/afl/src/timg+0x4a40c3)
#1 0x5179a8 in timg::UnicodeBlockCanvas::RequestBuffers(int, int) /home/xxx/timg-1.5.1/src/unicode-block-canvas.cc:424:42
#2 0x5179a8 in timg::UnicodeBlockCanvas::Send(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration) /home/xxx/timg-1.5.1/src/unicode-block-canvas.cc:322:26
#3 0x5126c6 in timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)::operator()(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&) const /home/xxx/timg-1.5.1/src/renderer.cc:50:22
#4 0x5126c6 in void std::__invoke_impl<void, timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration>(std::__invoke_other, timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int&&, int&&, timg::Framebuffer const&, timg::SeqType&&, timg::Duration&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:61:14
#5 0x5126c6 in std::enable_if<__and_<std::is_void<void>, std::__is_invocable<timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration> >::value, void>::type std::__invoke_r<void, timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration>(timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)&, int&&, int&&, timg::Framebuffer const&, timg::SeqType&&, timg::Duration&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:154:7
#6 0x5126c6 in std::_Function_handler<void (int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration), timg::(anonymous namespace)::SingleColumnRenderer::render_cb(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::'lambda'(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration const&)>::_M_invoke(std::_Any_data const&, int&&, int&&, timg::Framebuffer const&, timg::SeqType&&, timg::Duration&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_function.h:290:9
#7 0x5730d7 in std::function<void (int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration)>::operator()(int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration) const /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_function.h:590:9
#8 0x5730d7 in timg::STBImageSource::SendFrames(timg::Duration const&, int, int const volatile&, std::function<void (int, int, timg::Framebuffer const&, timg::SeqType, timg::Duration)> const&) /home/xxx/timg-1.5.1/src/stb-image-source.cc:163:13
#9 0x4e10eb in PresentImages(std::vector<std::future<timg::ImageSource*>, std::allocator<std::future<timg::ImageSource*> > >*, timg::DisplayOptions const&, timg::PresentationOptions const&, timg::BufferedWriteSequencer*, bool*) /home/xxx/timg-1.5.1/src/timg.cc:373:17
#10 0x4e10eb in main /home/xxx/timg-1.5.1/src/timg.cc:960:5
#11 0x7fa43c829d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/xxx/timg-1.5.1/src/unicode-block-canvas.cc:145:20 in void timg::StoreBacking<2>(timg::rgba_t*, timg::rgba_t const*, timg::rgba_t const*)
Shadow bytes around the buggy address:
0x0c247fff8030: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c247fff8040: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c247fff8050: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa
0x0c247fff8060: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0c247fff8070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c247fff8080: 00 00 00 00 00 00 00 00 00 00 00[04]fa fa fa fa
0x0c247fff8090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff80b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff80c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff80d0: 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
==2368346==ABORTING