这题主要考察文件包含的二次渲染。
思路借鉴自博客:https://blog.csdn.net/weixin_43571641/article/details/84667126 。
脚本工具来源于博客:https://xz.aliyun.com/t/2657 。
目录
源码复现
下面是我根据服务器行为进行的代码复现,主要代码来源于https://github.com/c0ny1/upload-labs/blob/master/Pass-16/index.php
。需要依赖于php-gd
模块,没有的话可以自行安装。
<?php
// 设置本地路径为上传路径
define('UPLOAD_PATH',dirname(__FILE__));
// 默认上传失败
$is_upload = false;
if (isset($_GET['type']) && $_GET['type'] === 'upload'){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES['file']['name'];
$filetype = $_FILES['file']['type'];
$tmpname = $_FILES['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/GIF/PNG格式的图片文件";
}
if($is_upload === true){
// 判断是否有字符串
if(strpos( file_get_contents($img_path), 'phpinfo()') === false){
$msg = "<img src=\"$newfilename\"><br>[Check Error]上传的图片源代码中未包含指定字符串:<font color=\"red\">phpinfo()</font>";
}else{
$msg = "<img src=\"$newfilename\"><br>[Success]Flag=DDCTF{B3s7_7ry_php1nf0_1d2667badf479fad}";
}
}
die($msg);
}
?>
<html>
<body>
<form action="upload.php?type=upload" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
赛题分析
先访问看看有什么提示。看到需要授权访问,但是题目已经给了用户名和密码,直接登录就行。
ex@Ex:~/test$ curl -v http://117.51.148.166/upload.php
* Trying 117.51.148.166...
* TCP_NODELAY set
* Connected to 117.51.148.166 (117.51.148.166) port 80 (#0)
> GET /upload.php HTTP/1.1
> Host: 117.51.148.166
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Server: nginx
< Date: Mon, 15 Apr 2019 02:05:03 GMT
< Content-Type: text/html
< Content-Length: 188
< Connection: keep-alive
< WWW-Authenticate: Basic realm="ddctf"
<
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host 117.51.148.166 left intact
下面是登录成功的网页:
<html>
<body>
<form action="upload.php?type=upload" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
随便上传一张图片试试。得到下面的回应:
<img src="image/190415100910_21035964.jpg"><br>[Check Error]上传的图片源代码中未包含指定字符串:<font color="red">phpinfo()</font>
直接加到文件尾部echo -n "phpinfo()" >> t.jpg
,再次上传还是上面的情况。把图片下载下来查看,发现原先被我们加在文件尾部的phpinfo()
不见了。应该是被渲染了。
二次渲染
构造图片时,我们可以将代码插入到图片不会被渲染的部分就行。
可以直接使用国外大牛编写的脚本jpg_payload.php
。
jpg_payload.php
下载:http://file.eonew.cn/ctf/web/jpg_payload.html
。
使用方法:php jpg_payload.php 1.jpg
,1.jpg为你要处理的图片,可以修改代码中的$miniPayload = "<?=phpinfo();?>";
来更改要传入的内容,然后上传处理好的图片,如果被绊住了,就把渲染的图片下载下来,继续用jpg_payload.php
处理,多试几次flag就出来了。
最终html
<img src="image/190415104238_533203990.jpg"><br>[Success]Flag=DDCTF{B3s7_7ry_php1nf0_1d2667badf479fad}
总结
有些原理不必深究,会用就行,人的时间是有限的,所以在学习时应该懂得取舍。