# ZBar Heap-based Buffer Overflow Vulnerability ### CVE Number CVE-2023-40889 ### Summary A heap-based buffer overflow exists in the *qr_reader_match_centers* function of ZBar 0.23.90. Specially crafted QR codes may lead to information disclosure and/or arbitrary code execution. To trigger this vulnerability, an attacker can digitally input the malicious QR code, or prepare it to be physically scanned by the vulnerable scanner. ### Tested Versions ZBar 0.23.90 ### Product URLs https://github.com/mchehab/zbar/releases/tag/0.23.90 <!-- ### Details --> <!-- When reading in an `.stl` file with the `--export-gcode` argument, `class PerimeterGenerator` is invoked. The class has some pointers to objects, but it does not provide a destructor and instead uses the default destructor. However, the default destructor only destroys the pointer, but not what the pointer was pointing to. Therefore, the allocated memories are not properly released upon the destruction of `class PerimeterGenerator`, leading to potential memory exhaustion. ```cpp=38 class PerimeterGenerator { public: // Inputs: const SurfaceCollection* slices; const ExPolygonCollection* lower_slices; double layer_height; int layer_id; Flow perimeter_flow; Flow ext_perimeter_flow; Flow overhang_flow; Flow solid_infill_flow; PrintRegionConfig* config; PrintObjectConfig* object_config; PrintConfig* print_config; // Outputs: ExtrusionEntityCollection* loops; ExtrusionEntityCollection* gap_fill; SurfaceCollection* fill_surfaces; PerimeterGenerator( // Input: const SurfaceCollection* slices, double layer_height, Flow flow, PrintRegionConfig* config, PrintObjectConfig* object_config, PrintConfig* print_config, // Output: // Loops with the external thin walls ExtrusionEntityCollection* loops, // Gaps without the thin walls ExtrusionEntityCollection* gap_fill, // Infills without the gap fills SurfaceCollection* fill_surfaces) : slices(slices), lower_slices(NULL), layer_height(layer_height), layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow), overhang_flow(flow), solid_infill_flow(flow), config(config), object_config(object_config), print_config(print_config), loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces), _ext_mm3_per_mm(-1), _mm3_per_mm(-1), _mm3_per_mm_overhang(-1) {}; void process(); private: double _ext_mm3_per_mm; double _mm3_per_mm; double _mm3_per_mm_overhang; Polygons _lower_slices_p; ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const; ExtrusionEntityCollection _variable_width (const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const; }; } ``` --> ### Crash Information ```sh ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6040000e1bf6 at pc 0x7f22e913836b bp 0x7fff893b6590 sp 0x7fff893b6588 READ of size 1 at 0x6040000e1bf6 thread T0 #0 0x7f22e913836a in qr_reader_match_centers /home/fuzzer/ramdisk_fuzz/ZBar/zbar/qrcode/qrdec.c:3903:18 #1 0x7f22e913a2ef in _zbar_qr_decode /home/fuzzer/ramdisk_fuzz/ZBar/zbar/qrcode/qrdec.c:4029:9 #2 0x7f22e910f004 in zbar_scan_image /home/fuzzer/ramdisk_fuzz/ZBar/zbar/img_scanner.c:806:5 #3 0x5503cb in zbar::ImageScanner::scan(zbar::Image&) /usr/local/include/zbar/ImageScanner.h:113:16 #4 0x5503cb in LLVMFuzzerTestOneInput /home/fuzzer/ramdisk_fuzz/libfuzz/src/fuzz.cpp:97 #5 0x42fb77 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x42fb77) #6 0x43a3e4 in fuzzer::Fuzzer::MutateAndTestOne() (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x43a3e4) #7 0x43ba4f in fuzzer::Fuzzer::Loop(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x43ba4f) #8 0x42ae0c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x42ae0c) #9 0x41dc82 in main (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x41dc82) #10 0x7f22e4ea1bf6 in __libc_start_main /build/glibc-S9d2JN/glibc-2.27/csu/../csu/libc-start.c:310 #11 0x41dd49 in _start (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x41dd49) 0x6040000e1bf6 is located 0 bytes to the right of 38-byte region [0x6040000e1bd0,0x6040000e1bf6) allocated by thread T0 here: #0 0x513488 in calloc (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x513488) #1 0x7f22e9133b0f in qr_reader_match_centers /home/fuzzer/ramdisk_fuzz/ZBar/zbar/qrcode/qrdec.c:3895:25 #2 0x7f22e913a2ef in _zbar_qr_decode /home/fuzzer/ramdisk_fuzz/ZBar/zbar/qrcode/qrdec.c:4029:9 #3 0x7f22e910f004 in zbar_scan_image /home/fuzzer/ramdisk_fuzz/ZBar/zbar/img_scanner.c:806:5 #4 0x5503cb in zbar::ImageScanner::scan(zbar::Image&) /usr/local/include/zbar/ImageScanner.h:113:16 #5 0x5503cb in LLVMFuzzerTestOneInput /home/fuzzer/ramdisk_fuzz/libfuzz/src/fuzz.cpp:97 #6 0x42fb77 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x42fb77) #7 0x43a3e4 in fuzzer::Fuzzer::MutateAndTestOne() (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x43a3e4) #8 0x43ba4f in fuzzer::Fuzzer::Loop(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, fuzzer::fuzzer_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x43ba4f) #9 0x42ae0c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x42ae0c) #10 0x41dc82 in main (/home/fuzzer/ramdisk_fuzz/libfuzz/fuzzer+0x41dc82) #11 0x7f22e4ea1bf6 in __libc_start_main /build/glibc-S9d2JN/glibc-2.27/csu/../csu/libc-start.c:310 ``` ### POC https://hackmd.io/_uploads/Bk1UnVKLa.png ![heap-6263cb80cbc92040e336f1a0b43bc239fa0af891](https://hackmd.io/_uploads/Bk1UnVKLa.png)