zoukankan      html  css  js  c++  java
  • [一道蓝鲸安全打卡Web分析] 文件上传引发的二次注入

    蓝鲸打卡的一个 web 文件上传引发二次注入的题解和思考

    蓝鲸文件管理系统

    源代码地址:http://www.whaledu.com/course/290/task/2848/show

    首先在设置文件里把所有的输入都采用 addslashes() 函数进行转义

    upload.php关键代码

    将上传的文件通过pathinfo()函数分成三个部分,[dirname] [filename] [extension]

    然后进行后缀名检查,拼接后进行addslashes转义,查询是否存在这个文件

    if($file["error"] == UPLOAD_ERR_OK) {
            $name = basename($file["name"]);
            $path_parts = pathinfo($name);
    
        if(!in_array($path_parts["extension"], array("gif", "jpg", "png", "zip", "txt"))) {
            exit("error extension");
        }
        $path_parts["extension"] = "." . $path_parts["extension"];
    
        $name = $path_parts["filename"] . $path_parts["extension"];
       
        $path_parts['filename'] = addslashes($path_parts['filename']);
    
        $sql = "select * from `file` where `filename`='{$path_parts['filename']}' and `extension`='{$path_parts['extension']}'";
        $fetch = $db->query($sql);
        if($fetch->num_rows>0) {
            exit("file is exists");
        }
    

    将文件名和后缀名插入数据库,将文件移动到相应文件夹并返回路径

    if(move_uploaded_file($file["tmp_name"], ROOT . UPLOAD_DIR . $name)) {
    
            $sql = "insert into `file` ( `filename`, `view`, `extension`) values( '{$path_parts['filename']}', 0, '{$path_parts['extension']}')";
            $re = $db->query($sql);
            if(!$re) {
                echo 'error';
                print_r($db->error);
                exit;
            }
            $url = "/" . UPLOAD_DIR . $name;
            echo "Your file is upload, url:
                <a href="{$url}" target='_blank'>{$url}</a><br/>
                <a href="/">go back</a>";
        } else {
            exit("upload error");
        }
    

    rename.php关键代码

    查询旧文件是否存在

    if(isset($req['oldname']) && isset($req['newname'])) {
        $result = $db->query("select * from `file` where `filename`='{$req['oldname']}'");
        if ($result->num_rows>0) {
            $result = $result->fetch_assoc();
        }else{
            exit("old file doesn't exists!");
        }
    

    更新filename,将oldname和newname重组,查询oldname是否存在,然后将文件的oldname更新为newname

    if($result) {       
    
        $req['newname'] = basename($req['newname']);
        $re = $db->query("update `file` set `filename`='{$req['newname']}', `oldname`='{$result['filename']}' where `fid`={$result['fid']}");
        if(!$re) {
            print_r($db->errorInfo());
            exit;
        }
        $oldname = ROOT.UPLOAD_DIR . $result["filename"].$result["extension"];
        $newname = ROOT.UPLOAD_DIR . $req["newname"].$result["extension"];
        if(file_exists($oldname)) {
            rename($oldname, $newname);
            $url = "/" . $newname;
            echo "Your file is rename, url:
                <a href="{$url}" target='_blank'>{$url}</a><br/>
                <a href="/">go back</a>";
        }
        else{echo $oldname." not exists.";}
    }
    

    解题思路

    在upload的过程中,全程进行转义并检测后缀,无法对上传进行操作,但是在rename的时候,没有对newname进行控制,这就可能会造成update的二次注入。

    假设我们上传的文件是 1.jpg,然后进行改名,这个时候就会触发数据库的update语句

    update `file` set `filename`='newname', `oldname`='1' where `fid`=fid

    很明显,这里的newname和oldname都是我们可以控制的。

    考虑上传问题,假设 1.jpg 是一句话木马,要把 1.jpg 变成 1.php,由于filename和extension分开操作,然后再合并,所有这里希望extension为空,这样在rename时可以将 1.jpg 变成 1.php。

    构造文件 ',extension='',filename='1.jpg.jpg,上传,进行rename为 1.php,发现结果为 1.php.jpg

    解释:

    文件 ',extension='',filename='1.jpg.jpg 上传后的数据库如下

    注意,rename过程中进行查询时,查询的结果 result['fid'] = 1,result['extension'] = 'jpg'

    然后进行update,这时执行了构造的SQL语句,数据库如下

    注意这两行代码

    $oldname = ROOT.UPLOAD_DIR . $result["filename"].$result["extension"];
    $newname = ROOT.UPLOAD_DIR . $req["newname"].$result["extension"];
    

    在这个过程中,oldname=',extension='',filename='1.jpg.jpg,newname=1.php.jpg,由于oldname存在,所以最后变成1.php.jpg

    解决

    构造文件 ',extension='',filename='1.jpg.jpg,上传,进行rename为 1.jpg,结果为 1.jpg.jpg

    构造另外一个一句话木马文件1.jpg,上传,数据库如下

    再进行rename,传入的oldname为 1.jpg,newname为 1.php

    进行查询的结果为 result['fid'] = 1,result['extension'] = ''

    在最后的过程中,oldname = 1.jpg,newname = 1.php,这样就把上传的 1.jpg 变成了 1.php

  • 相关阅读:
    「AtCoder AGC023F」01 on Tree
    「Wallace 笔记」平面最近点对 解法汇总
    「Codeforces 1181E」A Story of One Country (Easy & Hard)
    「NOI2018」「LOJ #2720」「Luogu P4770」 你的名字
    IdentityServer4设置RefreshTokenExpiration=Sliding不生效的原因
    【知识点】IQueryable.SumAsync方法的NULL异常
    Beyond Compare 4 密钥被吊销
    【知识点】Uri对象的完整地址
    git文件夹大小写问题
    .Net Core学习资料
  • 原文地址:https://www.cnblogs.com/peri0d/p/11508939.html
Copyright © 2011-2022 走看看