文件上传白名单绕过(图片马 - 图片二次渲染绕过)
文件上传白名单绕过(图片马 - 图片二次渲染绕过)
0x01:过关流程
本关的任务是上传一个 “图片马” 到服务器,然后利用文件包含漏洞来 Get Shell(本关要求三种格式的图片均要成功上传才可以,笔者下面演示的仅仅是 GIF 类型的绕过,主要是提供一个思路,对于另外两种格式的绕过,笔者后面会在 “文件上传漏洞” 中单独讲解如何制作一个高级的图片马):
查看源码,我们发现,本关使用的是白名单校验,且只接收三种图片类型的文件。当服务端收到用户上传的图片后,还会进行二次渲染,即在服务端重新生成一张和用户上传的图片类似的图片(底层还是修改了用户上传的图片,你嵌入其中的图片马很容易就被重写坏了):
如下,是笔者原本上传的一个 muma.jpg 与其后端渲染后的图片的对比,可以发现,基本上整张图片都被重写了,笔者写入一句话木马的地方也被重构了:
对于这种面目全非的图片,我们显然不能使用文件包含漏洞 Get Shell。但是,如果你使用的是 GIF 格式的图片马,你就会发现二次渲染后的内容中有很多相似的地方:
接下来,我们只要往这些相似的部分中找到一个合适的位置写入一句话木马然后上传即可(位置找不好的话,依旧有可能会被二次渲染掉哦,可以从服务器下载上传后的文件,然后查看其二进制信息中是否携带了木马信息):
找不会被渲染的位置也是一个难活,不同图片的位置都不太一样,而且由于你添加了内容,所以很可能原本不会被渲染的位置依旧被渲染了。不过思路就是上面这样,上传一个图片马,然后下载服务端二次渲染后的图片与原图片对比,看其中是否存在我们写入的一句话木马。
图片马上传成功后,我们还需要一个 “文件包含漏洞” 来执行图片马中的代码(靶场提供了,如果不知道怎么找,可以去看 PASS 14 中的内容):
如上,可以成功包含图片马,那么下面我们使用 ”中国蚁剑“ 来连接一下木马,看看能否 Get Shell(如下,Get Shell 成功,本关结束):
0x02:源码分析
下面是本关的 WAF 源码,使用的是白名单的过滤方式。虽然代码很多,但总体逻辑就是,如果你上传的文件属于白名单文件,它就会给你二次渲染一个类似的文件然后放在服务端中:
$is_upload = false;$msg = null;if (isset($_POST['submit'])){// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径$filename = $_FILES['upload_file']['name'];$filetype = $_FILES['upload_file']['type'];$tmpname = $_FILES['upload_file']['tmp_name'];$target_path=UPLOAD_PATH.'/'.basename($filename);// 获得上传文件的扩展名$fileext= substr(strrchr($filename,"."),1);//判断文件后缀与类型,合法才进行上传操作if(($fileext == "jpg") && ($filetype=="image/jpeg")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefromjpeg($target_path);if($im == false){$msg = "该文件不是jpg格式的图片!";@unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".jpg";//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;imagejpeg($im,$img_path);@unlink($target_path);$is_upload = true;}} else {$msg = "上传出错!";}}else if(($fileext == "png") && ($filetype=="image/png")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefrompng($target_path);if($im == false){$msg = "该文件不是png格式的图片!";@unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".png";//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;imagepng($im,$img_path);@unlink($target_path);$is_upload = true; }} else {$msg = "上传出错!";}}else if(($fileext == "gif") && ($filetype=="image/gif")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefromgif($target_path);if($im == false){$msg = "该文件不是gif格式的图片!";@unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".gif";//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = UPLOAD_PATH.'/'.$newfilename;imagegif($im,$img_path);@unlink($target_path);$is_upload = true;}} else {$msg = "上传出错!";}}else{$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";}}
笔者上面仅仅介绍了 GIF 图片的绕过方式,对于 .png 与 .jpg 其修改方式与 GIF 有很大区别,你还需要了解两种图片的底层格式和规则,所以就不放在这里了。后续还有会更多精彩内容,敬请期待噢。