upload-labs 17源码:
$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的图片文件!";
}
}
代码分析:
本关用到了二次渲染的文件上传操作手法,在实际业务场景中可能会遇到图片在上传时不会直接接受上传的图片,而是将上传的图片进行裁剪后上传,这是可能隐藏在图片中的图片马会在二次上传时丢失,这时就会用到二次渲染,接下来让我们对代码进行分析。
在代码第9行 使用basename()
获取上传文件名并拼接上传路径赋值给
t
a
r
g
e
t
p
a
t
h
,
在第十二行处获取了上传文件的后缀赋值给
target_path,在第十二行处获取了上传文件的后缀赋值给
targetpath,在第十二行处获取了上传文件的后缀赋值给filerxt,这里的1是有下标是从0开始,只获取.之后而不包括.。
代码第15行判断图片是为jpg并且请求头中的content-type是否为image/jpeg,在代码第18行处,使用
imagecreatefromjpeg()
函数判断再次判断图片类型是否为jpg,如果不是则在22行使用,unlink()函数对上传的文件进行删除,如果是jpg那么通过代码第29行的imagejpeg()生成新的jpg图片并保存到新的位置,这也就是上面说的图片的二次渲染,最后在将原来的图片删除。

定义和用法:
该函数是PHP中的内置函数,用于从JPEG文件或URL创建新图像。该图像可以在程序中进一步处理。
语法:
resource imagecreatefromjpeg( string $filename )
返回值:
成功时此函数返回图像资源标识符,错误时返回FALSE。
unline()
定义和用法:
该函数用于删除文件
语法:
unlink(filename,context)
filename 必需。规定要删除的文件。
context 可选。规定文件句柄的环境。context 是一套可以修改流的行为的选项。
返回值:
如果成功,该函数返回 TRUE。如果失败,则返回 FALSE。
imagepng()
定义和用法:
该函数是PHP中的内置函数,用于向浏览器或文件显示图像。此函数的主要用途是在浏览器中查看图像,将任
何其他图像类型转换为JPEG并更改图像质量。
语法:
bool imagejpeg( resource $image, int $to, int $quality )
$image:它指定要处理的图像资源。
$to (Optional):它指定将文件保存到的路径。
$quality (Optional):它指定图像的质量。
返回值:
如果成功,此函数将返回TRUE,否则将返回FALSE。
漏洞利用:
由于会将我们上传的图片马进行重新生成,这时可能会将包含在我们图片中的一句话木马在生成新图片
时丢失掉,从而导致我们的图片马无法发挥作用,但在生成新图片时有些地方是不会发生改变的,我们
可将一句话木马插入到不会改变的地方即可绕过上述判断代码,成功上传文件。
我们以 gif 图片为例, png 、 jpg 图片格式需要用到一些比较方便的py脚本进行生成,有兴趣的小伙伴
可以访问这篇文章进行学习:
https://blog.youkuaiyun.com/weixin_45588247/article/details/119177948
首先上传一张正常的 gif 图片,将二次渲染后的图片与原图片进行对比,找到没有被渲染的地方。
使用 Beyond Compare =》16进制比较,对比工具对两张图片进行比较发现很多地方在二次渲染的时候
没有进行变化
在渲染后的图片中没有渲染部分添加一句话木马(最好在上面一点的位置进行添加),并CTRL+S保存。
然后将修改后的图片再次上传,并使用 Beyond Compare 工具查看我们刚才上传的图片,发现我们插入
的一句话木马没有被二次渲染。