阻止人们上传GIF的方法是什么?

时间:2012-06-02 19:19:13

标签: php security image-processing gd code-injection

我有一个PHP网站,人们可以在这里填写帮助票。它允许他们上传票证的屏幕截图。我允许上传gif,psd,bmp,jpg,png,tif。收到上载后,PHP脚本将忽略文件扩展名。它仅使用MIME信息标识文件类型,对于这些文件类型,它始终存储在文件的前12个字节中。

有人上传了几个GIF,当用浏览器查看时,浏览器说它无效,我的病毒扫描程序提醒我它是注射(或类似的东西)。请参阅下面的包含这些GIF的zip文件。

我认为只检查标题信息是不够的。我听说图像可以完全有效,但也包含漏洞利用代码。

所以我有两个基本问题:

  1. 是否有人知道他们是如何将不良内容注入GIF(,同时仍保留有效的GIF MIME类型)?如果我知道这一点,也许我可以在上传时检查它。
  2. 如何阻止某人上传此类文件?
    • 我在共享主机上,因此无法安装服务器端病毒 扫描器。
    • 将信息提交到在线病毒扫描网站 可能太慢了。
    • 有没有办法检查自己使用检查这些东西的PHP类?
    • 如果图像无效,会使用GD调整图像大小吗?或者漏洞仍然会漏掉并进入已调整大小的图像?如果它失败了,那将是理想的,因为那时我可以使用调整大小作为一种技术来查看它们是否有效。

  3. 更新:所有人,感谢您回复至今。我试图在服务器上查找上传的GIF。如果我发现它,我会更新这篇文章。

    更新2:我为所有感兴趣的人找到了GIF。我把它们放在一个用密码“123”加密的zip文件中。它位于此处(请注意,此主机网站上有多个“下载”按钮 - 其中一些用于广告)http://www.filedropper.com/badgifs。名为5060.gif的版本被我的防病毒软件标记为特洛伊木马(TR / Graftor.Q.2)。我应该注意这些文件是在我实现前12个字节的MIME检查之前上传的。所以现在,我对这些特殊的安全。但我仍然想知道如何检测隐藏在正确MIME类型后面的漏洞。


    重要说明: 我只关心下载这些文件以查看它们的PC的风险。这些文件对我的服务器没有风险。它们不会被执行。它们使用扩展名为“.enc”的干净名称(十六进制散列输出)进行存储,然后使用fwrite过滤器将它们保存到加密状态的磁盘中:

    // Generate random key to encrypt this file.
    $AsciiKey = '';
    for($i = 0; $i < 20; $i++)
        $AsciiKey .= chr(mt_rand(1, 255));
    
    // The proper key size for the encryption mode we're using is 256-bits (32-bytes).
    // That's what "mcrypt_get_key_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)" says.
    // So we'll hash our key using SHA-256 and pass TRUE to the 2nd parameter, so we
    // get raw binary output.  That will be the perfect length for the key.
    $BinKey = hash('SHA256', '~~'.TIME_NOW.'~~'.$AsciiKey.'~~', true);
    
    // Create Initialization Vector with block size of 128 bits (AES compliant) and CBC mode
    $InitVec = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
    $Args = array('iv' => $InitVec, 'key' => $BinKey, 'mode' => 'cbc');
    
    // Save encoded file in uploads_tmp directory.
    $hDest = fopen(UPLOADS_DIR_TMP.'/'.$Hash.'.enc', 'w');
    stream_filter_append($hDest, 'mcrypt.rijndael-128', STREAM_FILTER_WRITE, $Args);
    fwrite($hDest, $Data);
    fclose($hDest);
    

7 个答案:

答案 0 :(得分:6)

对于第一个问题,您永远不会真正知道您是否无法检索任何日志或相关图片,因为这些漏洞利用可能会针对很多东西并依赖于关于利用文件放入文件的目标是什么,可能完全不同。

编辑: W32 / Graftor 是一个generic name,用于看似具有木马特征的程序。

在十六进制编辑器中打开文件5060.gif后,我注意到程序实际上是renamed windows program。虽然它不是浏览器漏洞,因此除非实际打开和执行,否则它是无害的,你必须确保它不是由上传者定义的MIME类型提供的,因为用户可能仍然被欺骗打开程序;看到第二个问题的答案。

至于第二个问题:为防止运行任何漏洞利用代码或用户,您必须确保所有文件都以文件名中的安全扩展名存储,以便提供服务使用正确的MIME类型。例如,您可以使用此正则表达式检查文件名:

if(!preg_match ( '/\\.(gif|p(sd|ng)|tiff?|jpg)$/' , $fileName)){
    header("415 Unsupported Media Type");
    die("File type not allowed.");
}

还要确保您使用正确的内容类型提供文件;确保在向用户提供文件时不使用上载文件指定的内容类型。如果您依赖上传者指定的Content-Type,则该文件可以作为text/html或类似的文件提供,并且将由用户的浏览器进行解析。

请注意,这只能防止恶意文件利用用户浏览器中的漏洞,图像解析器被排除在外。

如果你试图阻止对服务器的攻击,你必须确保你不会让PHP解析器执行图像的内容,并且你用来处理图像的图像库不会有任何已知的漏洞。

另请注意,此代码不会保护您免受包含用户浏览器使用的图像解析器漏洞的图像的攻击;为了防止这种情况,您可以按照Jeroen的建议检查getimagesize()是否评估为真。

请注意,如果您不检查文件名并确保使用正确的getimagesize()标头提供文件,仅使用Content-Type是不够的,因为完全有效的图像可以包含HTML / PHP代码嵌入内部评论。

答案 1 :(得分:2)

您可以使用getimagesize()功能。如果图片无效,则只会返回false

if (getimagesize($filename)) {
    // valid image
} else {
    // not a valid image
}

值得注意的是,这也不是100%安全,但据我所知,这是你能做到的最好的。

了解更多about this here

答案 2 :(得分:2)

您可以在任何接受上传的php脚本上尝试phpMussel。该文件将使用ClamAV签名扫描,以及一些内部启发式签名,专门寻找此类入侵。

答案 3 :(得分:1)

我不太了解图像格式,但重新创建图像然后存储结果,我觉得很有可能消除不必要的棘手的东西。特别是如果您删除所有元数据,如注释和某些图像格式支持的所有其他类型的可选嵌入字段。

答案 4 :(得分:0)

1)如果你删除了.gif并且你的A / V没有写日志,你永远不会确切地知道问题是什么。

问:有问题的.gif是否还在服务器上?

问:你检查过你的A / V日志了吗?

2)有许多不同的可能漏洞,可能与.gif文件格式有任何直接关系。这是一个例子:

3)为了降低此示例中的风险,您应该:

a)仅将文件(任何文件)上传到服务器上的安全目录

b)仅提供具有特定后缀(.gif,.png等)的文件

c)对于上传到您网站的任何内容极为偏执(特别是如果您允许其他人从您的网站下载它!)

答案 5 :(得分:0)

非常有用的提示,以防止注入PHP的问题来自我的主机的系统管理员:我有一个网站,人们可以上传自己的内容。我想确保提供上传图像的目录不运行任何PHP。这样,有人甚至可以发布名为“test.php”的图片,如果它在上传目录中,它仍然不会被PHP解析。解决方案很简单:在上传内容的文件夹中放入以下.htacess:

create trigger TRG_Insert_fDebtor on ABC.fDebtor
ON AFTER Insert
as
begin
    SET NOCOUNT ON;
    --- checking for the record exist in the DEF database 
    IF (select count(*) from DEF.fDebtor where exists(select * from inserted)) > 0
    begin
        ----- insert record in your other database  DEF
        insert into DEF.fDebtor values ()
    end
end

这将关闭文件夹的PHP引擎,从而停止任何尝试启动任何PHP以利用服务器端漏洞。

答案 6 :(得分:0)

迟到的回复,但可能对某人有用。 您可以尝试这样的方法:

//saves filtered $image to specified $path
function save($image,$path,$mime) {
    switch($mime) {
        case "image/jpeg"   : return imagejpeg(imagecreatefromjpeg($image),$path);
        case "image/gif"    : return imagegif(imagecreatefromgif($image),$path);
        case "image/png"    : return imagepng(imagecreatefrompng($image),$path);
    }
    return false;
};