Sec Bug->Bug #79385 [Opn->Nab]: Global Out-of-Bounds Read

From: Date: Mon, 16 Mar 2020 08:01:00 +0000
Subject: Sec Bug->Bug #79385 [Opn->Nab]: Global Out-of-Bounds Read
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-226120@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=79385&edit=1 ID: 79385 Updated by: cmb@php.net Reported by: dev dot davidmatosse at outlook dot com Summary: Global Out-of-Bounds Read -Status: Open +Status: Not a bug -Type: Security +Type: Bug Package: GD related Operating System: Linux PHP Version: Irrelevant -Assigned To: +Assigned To: cmb Block user comment: N Private report: Y New Comment: > Both arguments of presented functions > (gdImageCreateFromWebpPtr(int size, void *data) and > gdImageCreateFromJpegPtr(int size, void *data)) are user supplied > data with no prior sanitize. No, they are not. Of course, the client of libgd is supposed to pass valid values, just like when calling memcpy(), for instance. Previous Comments: ------------------------------------------------------------------------ [2020-03-16 00:03:48] stas@php.net I imagine this has to be reported to libgd maintainers? Especially given it reproduces without PHP in the picture at all? Or the problem is already fixed in libgd and PHP bundled one is behind? ------------------------------------------------------------------------ [2020-03-15 15:06:10] cmb@php.net Tentatively assessing as security issue. ------------------------------------------------------------------------ [2020-03-15 14:44:55] dev dot davidmatosse at outlook dot com Description: ------------ While analysing the source code of libgd (located at github.com/libgd/libgd [1] and bundled version of php 7.4.3 [2]) was found that there is a global out-of-bounds read error in function dynamicGetbuf (gd_io_dp.c [3]), called by gdImageCreateFromWebpPtr or gdImageCreateFromJpegPtr functions. Both arguments of presented functions (gdImageCreateFromWebpPtr(int size, void *data) and gdImageCreateFromJpegPtr(int size, void *data)) are user supplied data with no prior sanitize. Whatever the call context in which we have size > that the length of the data, we trigger the global out-of-bounds read. > Study Case 1 - gdImageCreateFromWebpPtr [4] is a function used to load truecolor or create images from WebP data already in memory. The function have two argumets, a size of the data in bytes and a pointer to data (WebP data). In attempt to create the Webp image from data already in memory, we call the function gdImageCreateFromWebpPtr and pass to then 2 arguments (user controlled data), this information is used to create the gdIOCtx [5] and we pass to gdImageCreateFromWebpCtx [6] to create the image. 2 - on function gdImageCreateFromWebpCtx, in attempt to get the number of bytes read from gdIOCtx we call gdGetBuf [7] which is resolved dynamically to dynamicGetbuf [8] 3 - at this point we have the following rlen = size dp->data = data if we call the memcpy [9] with rlen set to length greater than the source (dp->data), it results in global out-of-bounds read. > conclusion After digging into the code a little further was found that to reach the vulnarable function [8], we need a following call stack @whatever_function@ --> gdGetBuf(dest, size, src) --> dynamicGetbuf(src_pkd, dest, size) --> memcpy(dest, src, size); [where 'size' and 'data' are user controllable] As example we have: gdImageCreateFromWebpPtr and gdImageCreateFromJpegPtr > references [1] - https://github.com/libgd/libgd [2] - https://www.php.net/downloads.php#v7.4.3 [3] - https://github.com/libgd/libgd/blob/master/src/gd_io_dp.c [4] - https://github.com/libgd/libgd/blob/master/src/gd_webp.c#L86 [5] - https://github.com/libgd/libgd/blob/master/src/gd_webp.c#L89 [6] - https://github.com/libgd/libgd/blob/master/src/gd_webp.c#L102 [7] - https://github.com/libgd/libgd/blob/master/src/gd_io.c#L211 [8] - https://github.com/libgd/libgd/blob/master/src/gd_io_dp.c#L270 [9] - https://github.com/libgd/libgd/blob/master/src/gd_io_dp.c#L302 Test script: --------------- /* file: poc.c to build: clang-9 poc.c -o poc -lgd -fsanitize=address */ #include <gd.h> int main(){ int size = 16; void *data = "AAAAAAAAAAAA"; gdImageCreateFromWebpPtr (size, data); return 0; } Expected result: ---------------- Webp image generated. Actual result: -------------- ==1611==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000004d4c1c at pc 0x000000431bb7 bp 0x7ffe7ebd0ef0 sp 0x7ffe7ebd06b0 READ of size 48 at 0x0000004d4c1c thread T0 #0 0x431bb6 in memcpy (~/poc/poc+0x431bb6) #1 0x7f57a1f5a368 in dynamicGetbuf ~/libgd/src/gd_io_dp.c:302:2 #2 0x7f57a1f59fb7 in gdGetBuf ~/libgd/src/gd_io.c:213:9 #3 0x7f57a1f68dd2 in gdImageCreateFromWebpCtx ~/libgd/src/gd_webp.c:126:7 #4 0x7f57a1f69061 in gdImageCreateFromWebpPtr ~/libgd/src/gd_webp.c:92:7 #5 0x4c222f in main (~/poc/poc+0x4c222f) #6 0x7f57a103882f in __libc_start_main /build/glibc-LK5gWL/glibc-2.23/csu/../csu/libc-start.c:291 #7 0x41ac48 in _start (~/poc/poc+0x41ac48) 0x0000004d4c1c is located 0 bytes to the right of global variable '<string literal>' defined in 'poc.c:10:16' (0x4d4c00) of size 28 '<string literal>' is ascii string 'AAAAAAAAAAAAAAAAAAAAAAAAAAA' SUMMARY: AddressSanitizer: global-buffer-overflow (~/poc/poc+0x431bb6) in memcpy Shadow bytes around the buggy address: 0x000080092930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x000080092940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x000080092950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x000080092960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x000080092970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x000080092980: 00 00 00[04]f9 f9 f9 f9 00 00 00 00 00 00 00 00 0x000080092990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800929a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800929b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800929c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800929d0: 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 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 Shadow gap: cc ==1611==ABORTING ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=79385&edit=1

« previous php.bugs (#226120) next »