Vulnerabilities > CVE-2016-8710 - Out-of-bounds Write vulnerability in Libbpg Project Libbpg 0.9.4/0.9.7

047910
CVSS 7.8 - HIGH
Attack vector
LOCAL
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
HIGH
Integrity impact
HIGH
Availability impact
HIGH
local
low complexity
libbpg-project
CWE-787

Summary

An exploitable heap write out of bounds vulnerability exists in the decoding of BPG images in Libbpg library. A crafted BPG image decoded by libbpg can cause an integer underflow vulnerability causing an out of bounds heap write leading to remote code execution. This vulnerability can be triggered via attempting to decode a crafted BPG image using Libbpg.

Vulnerable Configurations

Part Description Count
Application
Libbpg_Project
2

Common Weakness Enumeration (CWE)

Seebug

bulletinFamilyexploit
description### Summary An exploitable heap write out of bounds vulnerability exists in the decoding of BPG images in libbpg library. A crafted BPG image decoded by libbpg can cause an integer underflow vulnerability causing an out of bounds heap write leading to remote code execution. This vulnerability can be triggered via attempting to decode a crafted BPG image using libbpg. ### Tested Versions Libbpg - 0.9.4 and 0.9.7 ### Product URLs http://bellard.org/bpg/bpg_spec.txt ### CVSSv3 Score 7.5 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H ### Details BPG (Better Portable Graphics) is an image format created in 2014 based on the HECV video compression standard. BPG has been praised for its ability to produce the same quality image as JPEG or JPEG XR, but in a much smaller file size. It is currently in line to be incorporated in the multimedia player VLC. During the decoding of a BPG, in the `restore_tqb_pixels function`, an attacker controlled integer underflow can occur [1] during the calculation of offsets for the `src` and `dst` operands of a `mempcy`. Because of the underflows, the resulting addresses passed to the `memcpy` [2] are outside the bounds of the original heap structures, resulting in an out of bounds write condition. ``` libavcodec/hecv_filter.c: static void restore_tqb_pixels(HEVCContext *s, uint8_t *src1, const uint8_t *dst1, ptrdiff_t stride_src, ptrdiff_t stride_dst, int x0, int y0, int width, int height, int c_idx) { if ( s->pps->transquant_bypass_enable_flag || (s->sps->pcm.loop_filter_disable_flag && s->sps->pcm_enabled_flag)) { int x, y; int min_pu_size = 1 << s->sps->log2_min_pu_size; int hshift = s->sps->hshift[c_idx]; int vshift = s->sps->vshift[c_idx]; int x_min = ((x0 ) >> s->sps->log2_min_pu_size); int y_min = ((y0 ) >> s->sps->log2_min_pu_size); int x_max = ((x0 + width ) >> s->sps->log2_min_pu_size); int y_max = ((y0 + height) >> s->sps->log2_min_pu_size); int len = (min_pu_size >> hshift) << s->sps->pixel_shift; for (y = y_min; y < y_max; y++) { for (x = x_min; x < x_max; x++) { if (s->is_pcm[y * s->sps->min_pu_width + x]) { int n; uint8_t *src = src1 + (((y - y0 [1]) << s->sps->log2_min_pu_size) >> vshift) * stride_src + ((((x - x0 [1]) << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift); const uint8_t *dst = dst1 + (((y - y0 [1]) << s->sps->log2_min_pu_size) >> vshift) * stride_dst + ((((x - x0 [1]) << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift); for (n = 0; n < (min_pu_size >> vshift); n++) { memcpy(src, dst, len); [2] src += stride_src; dst += stride_dst; } } } } } } ``` ### Crash Information ``` ==23992== Invalid write of size 2 ==23992== at 0x4C32723: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23992== by 0x47C057: memcpy (string3.h:53) ==23992== by 0x47C057: restore_tqb_pixels (hevc_filter.c:281) ==23992== by 0x47D309: sao_filter_CTB (hevc_filter.c:522) ==23992== by 0x486794: ff_hevc_hls_filter (hevc_filter.c:948) ==23992== by 0x4870F5: ff_hevc_hls_filters (hevc_filter.c:979) ==23992== by 0x41CC84: hls_decode_entry (hevc.c:2388) ==23992== by 0x45B9BC: avcodec_default_execute (utils.c:121) ==23992== by 0x4255B6: hls_slice_data (hevc.c:2410) ==23992== by 0x4255B6: decode_nal_unit (hevc.c:2842) ==23992== by 0x4255B6: decode_nal_units (hevc.c:3089) ==23992== by 0x4255B6: hevc_decode_frame (hevc.c:3216) ==23992== by 0x45DD1E: avcodec_decode_video2 (utils.c:242) ==23992== by 0x403438: decode_write_data (libbpg.c:185) ==23992== by 0x403438: hevc_decode_frame (libbpg.c:302) ==23992== by 0x40872C: hevc_decode (libbpg.c:466) ==23992== by 0x40872C: bpg_decoder_decode (libbpg.c:1675) ==23992== by 0x402706: main (bpgdec.c:330) ==23992== Address 0x54351f0 is 12 bytes after a block of size 20 alloc'd ==23992== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==23992== by 0x460E2F: av_malloc (mem.c:138) ==23992== by 0x460E2F: av_malloc_array (mem.c:563) ==23992== by 0x4264E5: hls_slice_header (hevc.c:734) ==23992== by 0x4264E5: decode_nal_unit (hevc.c:2770) ==23992== by 0x4264E5: decode_nal_units (hevc.c:3089) ==23992== by 0x4264E5: hevc_decode_frame (hevc.c:3216) ==23992== by 0x45DD1E: avcodec_decode_video2 (utils.c:242) ==23992== by 0x403438: decode_write_data (libbpg.c:185) ==23992== by 0x403438: hevc_decode_frame (libbpg.c:302) ==23992== by 0x40872C: hevc_decode (libbpg.c:466) ==23992== by 0x40872C: bpg_decoder_decode (libbpg.c:1675) ==23992== by 0x402706: main (bpgdec.c:330) In the above valgrind output, an out of bounds write is recorded. ``` ### Mitigation The following patch will fix the vulnerability, but it is untested as to whether it breaks any legitimate images. ``` diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c index 47678b5..d5515c2 100644 --- a/libavcodec/hevc_filter.c +++ b/libavcodec/hevc_filter.c @@ -222,8 +222,9 @@ static void restore_tqb_pixels(HEVCContext *s, for (x = x_min; x < x_max; x++) { if (s->is_pcm[y * s->sps->min_pu_width + x]) { int n; - uint8_t *src = src1 + (((y - y0) << s->sps->log2_min_pu_size) >> vshift) * stride_src + ((((x - x0) << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift); - const uint8_t *dst = dst1 + (((y - y0) << s->sps->log2_min_pu_size) >> vshift) * stride_dst + ((((x - x0) << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift); + + uint8_t *src = src1 + (((y << s->ps.sps->log2_min_pu_size) - y0) >> vshift) * stride_src + ((((x << s->ps.sps->log2_min_pu_size) - x0) >> hshift) << s->ps.sps->pixel_shift); + const uint8_t *dst = dst1 + (((y << s->ps.sps->log2_min_pu_size) - y0) >> vshift) * stride_dst + ((((x << s->ps.sps->log2_min_pu_size) - x0) >> hshift) << s->ps.sps->pixel_shift); for (n = 0; n < (min_pu_size >> vshift); n++) { memcpy(src, dst, len); ``` ### Timeline * 2016-10-20 - Vendor Disclosure * 2017-01-23 - Public Release ### CREDIT * Discovered by Cory Duplantis of Cisco Talos.
idSSV:96583
last seen2017-11-19
modified2017-09-26
published2017-09-26
reporterRoot
titleLibbpg BGP image decoding Code Execution Vulnerability(CVE-2016-8710)

Talos

idTALOS-2016-0223
last seen2019-05-29
published2017-01-23
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2016-0223
titleLibbpg BGP image decoding Code Execution Vulnerability