PHP EXIF进程IFD标记远程整数溢出

PHP EXIF进程IFD标记远程整数溢出,php,apache,exif,integer-overflow,Php,Apache,Exif,Integer Overflow,背景: 我一直在研究一个问题,即文件上传表单只接受特定的图像,这不是图像大小(维度)或大小(文件大小)的问题,但我认为我发现这与图像位深度有关,因为PHP脚本调整图像大小并应用静态(半透明)将水印文件添加到图像并保存结果 我今天和昨天都经历了一个漫长的过程,因为出现的错误是服务器声明“由服务器重置连接”。我想我已经缩小到服务器没有足够的空闲内存来完成图像资源操作 问题: 然后,在所有这些之后,在提交文件上载时会出现以下错误: 检测到“WEB PHP EXIF进程IFD标记远程整数溢出-2(CVE

背景:

我一直在研究一个问题,即文件上传表单只接受特定的图像,这不是图像大小(维度)或大小(文件大小)的问题,但我认为我发现这与图像位深度有关,因为PHP脚本调整图像大小并应用静态(半透明)将水印文件添加到图像并保存结果

我今天和昨天都经历了一个漫长的过程,因为出现的错误是服务器声明“由服务器重置连接”。我想我已经缩小到服务器没有足够的空闲内存来完成图像资源操作

问题:

然后,在所有这些之后,在提交文件上载时会出现以下错误:

检测到“WEB PHP EXIF进程IFD标记远程整数溢出-2(CVE-20/缓冲区溢出)”的IP

一些谷歌搜索只告诉我,这是PHP<4.2的安全漏洞,与实际情况无关

我已经看过我的代码,并且非常确定 我的问题是试图阐明这个错误语句的含义(以及我如何着手纠正它)

注意事项:

  • PHP 5.6.16

  • 页面上没有运行PHP EXIF函数

  • 我在页面上看不到任何会导致整数溢出的地方(我想是无限大)

  • 页面确实使用了
    imagecopy
    imagealphabling
    imagesavealpha
    ,但此错误通知似乎出现在脚本在上载文件上运行之前

  • 此错误仅发生在某些上载的图像上,而不发生在其他图像上

  • 我没有发现与此相关的Apache错误日志

  • 我没有记录PHP错误

代码:

由于我认为问题可能会在页面加载之前以某种方式出现,我不确定此代码块是否有用,但请看一下:

(另外请注意,我知道这个页面已经5年了,不是最聪明的编程,我已经对它进行了部分修复,但我知道它可能会被进一步整理)


听起来你有一个转发IP,它阻止上传可能会出错的图像。@bishop非常感谢这个链接。我在理解布局/信息方面有点困难。从错误报告的详细信息来看,它已经关闭了,所以我认为如果我下载并用
ext/ex替换服务器版本exif,我的想法是否正确如果/exif.c
链接到bug修复程序,那么应该对其进行排序。很抱歉,可能是一个明显的问题:-/我认为升级PHP不会修复此错误,原因有两个。首先,此错误字符串不存在于5.6版的PHP exif扩展源代码中,这表明您正在使用。其次,错误字符串包含字符串“IPS”,这向我强烈建议,有一个入侵保护系统硬件/软件组件正在PHP获取图像之前扫描EXIF。@bishop谢谢,我想我是充满希望的!我已经看过WHM,但没有看到相应的防火墙程序的迹象(因此我猜它可能超出了WHM的范围)乐观一点也没有坏处!请发布您正在使用的托管提供商和服务器操作系统。这可能有助于确定源代码。听起来您有一个转发IP,阻止上传可能会出错的图像。@bishop非常感谢看起来像这样的链接。我在理解布局/信息方面有点困难。由于错误报告详细信息,它已关闭,因此如果我下载服务器版本exif并将其替换为从错误修复程序链接的
ext/exif/exif.c
,那么我的想法是否正确,应该对其进行排序。很抱歉,可能是一个明显的问题:-/我认为升级PHP不会修复此错误,原因有两个。首先,此错误字符串不存在于PHP exif ex中表示正在使用的版本5.6的源代码。其次,错误字符串包含字符串“IPS”,这向我强烈建议,有一个入侵保护系统硬件/软件组件正在PHP获取图像之前扫描EXIF。@bishop谢谢,我想我是充满希望的!我已经看过WHM,但没有看到相应的防火墙程序的迹象(因此我猜它可能超出了WHM的范围)乐观一点也没有坏处!请发布您正在使用的主机提供商和服务器操作系统。这可能有助于确定源代码。
<?php
session_start();
error_reporting(E_ALL);
ini_set('display_errors', 1);
///first set out variables.

$goodImage = 0;
$maxfilesize = (int)$_POST['MAX_FILE_SIZE'];
$gallery = (int)$_POST['galfolderid']
if (empty($gallery)) {
    $_SESSION['message'] = $gallery . "<br/>Gallery Value has not been set.";
}
elseif (!is_numeric($gallery)) {
    $_SESSION['message'] = $gallery . "<br/>Gallery Value is not a numeric value.";
}
elseif (!is_dir($_SERVER['DOCUMENT_ROOT']."/images/gallery/" . $gallery )) {
    $_SESSION['message'] = $gallery . "<br/>Gallery Value, while being a number, is not a valid numeric value.";
}
if(!empty($_SESSION['message'])) {
    header("Location:editgallery.php?gallery=".$galleryid);
    exit;
}
for($count=0;$count<5;$count++) {
    if ($_FILES['image']['error'][$count] == 0) {
        clearstatcache();
        $finfo     = finfo_open(FILEINFO_MIME_TYPE);
        $imageType = finfo_file($finfo, $_FILES['image']['tmp_name'][$count]);
        finfo_close($finfo);
        unset($finfo);

        if (strtolower($imageType) == "image/png") {
            $imgtype  = "PNG";
            $original = imagecreatefrompng($_FILES['image']['tmp_name'][$count]);
        } elseif (strtolower($imageType) == "image/jpeg" || strtolower($imageType) == "image/jpg") {
            $imgtype  = "JPG";
            $original = imagecreatefromjpeg($_FILES['image']['tmp_name'][$count]);
        } else {
            //not a JPG or PNG type... set error.
            $_SESSION['message'] = "Image " . ($count+1) . " does not appear to be a valid .JPG or .PNG file. ";
            error_log($_SESSION['message']);
            header("Location:editgallery.php");
            exit;
        }
        unlink($_FILES['image']['tmp_name'][$count]);

        $edgePadding    = (int)$_POST['WMedge'][$count]; //integer
        $watermarkScale = $_POST['WMscale'][$count]; //float
        $h_position     = $_POST['Hpos'][$count]; //text array
        $v_position     = $_POST['Vpos'][$count]; //text array

        $Hoz = $h_position[0];
        $Vez = $v_position[0];


        if (!isset($watermarkScale) || empty($watermarkScale) || !is_numeric($watermarkScale)) {
            $watermarkScale = 1.0;
        }
        elseif($watermarkScale > 2.0) {
            $watermarkScale = 2.0;
        }
        elseif($watermarkScale < 0.5) {
            $watermarkScale = 0.5;
        }
        if ((!isset($edgePadding) || empty($edgePadding) || !is_numeric($edgePadding)) && $edgePadding !== "0") {
            $edgePadding = 5;
        }
        // be sure that the other options we need have some kind of value

        if ($_FILES['image']['size'][$count] > $maxfilesize) {
            $_SESSION['message'] .= "Image file ".($count+1)." appears to be too big. There is a limit of 2Mb on the
            size of the image you can upload. Please click 'Back' on your browser and resubmit a valid image.";
            error_log($_SESSION['message']);
            //file too big.
        }

        //target name is the number of images in the LARGE gallery,
        ///cycle through imagenames to find the first "clear" image number.
        $newimagename = 1;
        clearstatcache();
/***
NOTE: Only possible place an integer oveflow might occur I think
***/

        while (file_exists($_SERVER['DOCUMENT_ROOT'] . "/images/gallery/" . $gallery . "/S/" . $newimagename . ".jpg")) {
            $newimagename++;
        }
        ///newimagename is the new filename of the image.


        $target_name = $newimagename . ".jpg";
        $target      = $_SERVER['DOCUMENT_ROOT'] . "/images/gallery/" . $gallery . "/L/" . $target_name;
        $targetSmall    = $_SERVER['DOCUMENT_ROOT'] . "/images/gallery/" . $gallery . "/S/" . $target_name;
        //targetSM is used below to make the thumbnail image. for the SMALL gallery.
        //full target directory and name.
        // file upload success
        // now file need resizing before the watermark is applied.

        // resize new dimensions (Large- 800px)
        $originalImageSize[0] = imagesx($original);
        $originalImageSize[1] = imagesy($original);

        /***
        * Resize new dimensions for small thumbnail.
        ***/
        if ($originalImageSize[0] > 133) {
            $percent = 133 / $originalImageSize[0];
        } else {
            $percent = 1;
        }

        $newThumbHeight = $originalImageSize[1] * $percent;
        $newThumbWidth  = $originalImageSize[0] * $percent;

        // Resample
        $imageThumbFinal = imagecreatetruecolor($newThumbWidth, $newThumbHeight);

        imagecopyresampled($imageThumbFinal, $original, 0, 0, 0, 0, $newThumbWidth, $newThumbHeight, $originalImageSize[0], $originalImageSize[1]);

        // Output
        imagejpeg($imageThumbFinal, $targetSmall, 80);
        imagedestroy($imageThumbFinal);
        unset($imageThumbFinal, $percent,$newThumbWidth,$newThumbHeight);
        /***
         * End Thumbnail generation.
         */

        /***
         * Resize main sized image (max 800px wide)
         ***/
        if ($originalImageSize[0] > 800) {
            $percent = 800 / $originalImageSize[0];
        } else {
            $percent = 1;
        }

        $newPictureHeight = $originalImageSize[1] * $percent;
        $newPictureWidth  = $originalImageSize[0] * $percent;

        // Resample main image to reduce max size.
        $imageCleanFinal = imagecreatetruecolor($newPictureWidth, $newPictureHeight);

        imagecopyresampled($imageCleanFinal, $original, 0, 0, 0, 0, $newPictureWidth, $newPictureHeight, $originalImageSize[0], $originalImageSize[1]);


        /***
         * Now resize the watermark and save onto the final image.
         ***/
        //full target directory and name.
        $watermark = $_SERVER['DOCUMENT_ROOT'] . "/images/watermark2.png";
        $wmTarget  = substr($watermark, 0, -3) . "tmp"; //image/watermark2.tmp is resized.
        $sourceWaterImage   = imagecreatefrompng($watermark);
        $waterMarkWidth  = imagesx($sourceWaterImage);
        $waterMarkHeight = imagesy($sourceWaterImage);

        $destinationHeight = $waterMarkHeight * $watermarkScale;
        $destinationWidth  = $waterMarkWidth * $watermarkScale;

        $destinationHeight  = floor($destinationHeight);
        $destinationWidth = floor($destinationWidth);
        $destinationWatermarkImage = imagecreatetruecolor($destinationWidth, $destinationHeight);
        imagealphablending($destinationWatermarkImage, FALSE);
        imagesavealpha($destinationWatermarkImage, TRUE);

        imagecopyresampled($destinationWatermarkImage, $sourceWaterImage, 0, 0, 0, 0, $destinationWidth,
            $destinationHeight, $waterMarkWidth, $waterMarkHeight);
        imagedestroy($sourceWaterImage);
        unset($sourceWaterImage);
        clearstatcache();

        /***
         * Set watermark location on final image.
         ***/
        $differenceX = $newPictureWidth - $destinationWidth;
        $differenceY = $newPictureHeight - $destinationHeight;

        switch ($Hoz) {
            // find the X coord for placement
            case 'left':
                $placementX = $edgePadding;
                break;
            case 'center':
                $placementX = round($differenceX / 2);
                break;
            case 'right':
                $placementX = $newPictureWidth - ($destinationWidth + $edgePadding);
                break;
            default:
                $placementX = 0;
                break;
        }
        switch ($Vez) {
            // find the Y coord for placement
            case 'top':
                $placementY = $edgePadding;
                break;
            case 'middle':
                $placementY = round($differenceY / 2);
                break;
            case 'bottom':
                $placementY = $newPictureHeight - ($destinationHeight + $edgePadding);
                break;
            default:
                $placementY = 0;
                break;
        }
        /***
         * Finish set Watermark location
         ***/
        imagecopy($imageCleanFinal,
            $destinationWatermarkImage,
            $placementX,
            $placementY,
            0,
            0,
            $destinationWidth,
            $destinationHeight);

        imagejpeg($imageCleanFinal, $target, 80);

        /***
         * Image final save
         ***/
        // Output
        imagejpeg($imageCleanFinal, $target, 80);
        imagedestroy($imageCleanFinal);
        imagedestroy($destinationWatermarkImage);
        unset($imageCleanFinal, $percent);
        unlink($wmTarget);
        $output[$goodImage]['targetName'] = $target_name;
        $output[$goodImage]['targetAddr'] = $target;
        $goodImage++;

    } elseif (!isset($_FILES['image']['name'][$count]) || ($_FILES['image']['error'][$count] != 0 && $_FILES['image']['error'][$count] != 4)) {
        //error in file upload.
        $_SESSION['message'] .= " There is a file upload error number " . $_FILES['image']['error'][$count] . ". for image ".($count+1).".
         Please try resubmitting a valid image.";
        error_log($_SESSION['message']);
    }
}
if (empty($_SESSION['message'])){
    $_SESSION['message'] = $goodImage." New Image(s) Uploaded";
}
// display resulting image for download
header("Location:editgallery.php?special=yes&gallery=".$galleryid);
exit;