简介

在第16关中,解决方法与第14和第15关类似,都是通过修改文件头来绕过文件上传验证。然而,第16关额外使用了 php_exif模块对文件进行校验。因此,在尝试解决这一关时,需要确保php_exif模块已启用,如下图所示:

php_exif.dll–找不到指定的模块
要想php_exif能够被成功加载,必须满足下面条件:

  1. php_mbstring.dll 被启用;
  2. php.ini中,php_mbstring.dll 必须在php_exif.dll 前被加载。

攻击思路

下面是第16关关键源码部分:

function isImage($filename){
    //需要开启php_exif模块
    $image_type = exif_imagetype($filename);
    switch ($image_type) {
        case IMAGETYPE_GIF:
            return "gif";
            break;
        case IMAGETYPE_JPEG:
            return "jpg";
            break;
        case IMAGETYPE_PNG:
            return "png";
            break;    
        default:
            return false;
            break;
    }
}

这段代码实现了一个简单的函数 isImage,用于检查上传文件是否为图片文件。具体来说,它使用 exif_imagetype 函数来检测文件的 MIME 类型,并返回相应的文件扩展名。代码看起来直观,但仍然存在一些潜在的问题和漏洞。
exif_imagetype 只检查文件的前几个字节,这意味着攻击者可以通过在恶意文件(如 PHP 脚本)前面添加几个合法图片文件的字节,来欺骗这个函数。

解法步骤

  1. 构造webshell脚本

在桌面上新建一个名为webshell.php的脚本,内容如下所示:

GIF89a
<?php phpinfo(); ?>

其中GIF89awebshell脚本伪装GIF图片绕过文件上传验证。

补充知识:

  • Png图片文件包括8字节:89 50 4E 47 0D 0A 1A 0A。即为 .PNG
  • Jpg图片文件包括2字节:FF D8
  • Gif图片文件包括6字节:47 49 46 38 39|37 61 。即为 GIF89(7)a
  • Bmp图片文件包括2字节:42 4D。即为 BM

上传成功后,如下图所示:

  1. 验证上传结果

尝试访问上传的文件并执行命令。例如,访问 http://localhost/include.php?file=upload/2020240807164252.gif,返回如下信息,则说明文件上传绕过成功。