前言php
昨天在易霖博搞的网络安全与执法竞赛看到的一道web题,实际上就是用两个原题凑起来的。。git
不事后面的一关没见过这里简单记录一下github
第一关web
打开是个登陆界面,和BJDCTF的简单注入如出一辙,连密码都同样。。数组
第二关浏览器
登陆后获得安全
即网络
<?php ini_set('display_errors', 1); error_reporting(E_ALL); include 'flag.php'; //defines $flag class B { function __destruct() {//当一个对象销毁时被调用或者脚本结束时调用 global $flag; echo $flag; } } if (isset($_POST['payload'])) { ob_start();//打开输出缓冲区,全部的输出信息不在直接发送到浏览器,而是保存在输出缓冲区里面,可选得回调函数用于处理输出结果信息。 $a = unserialize($_POST['payload']); if ($a === False) { ob_end_clean();//清空(擦除)缓冲区并关闭输出缓冲 } throw new Exception('Something tragic happened');//抛出一个错误 } ?>
仍是原题 Websec level 30app
payload:ide
a:2:{i:0;O:1:"B":0:{}i:0;i:1;}
详细能够参考:
[https://kangwoosun.github.io/webhacking/2020/03/28/Websec/]
[https://www.evonide.com/breaking-phps-garbage-collection-and-unserialize/#comments]
[https://www.evonide.com/fuzzing-unserialize/]
如下是我的的浅薄理解
若是传入一个序列化的数组,而且这个数组中存在两个或多个key相等的变量,那么反序列化的时侯将删除首先输入的变量。所以,若是将类 B 对象做为value冗余,则将调用析构函数,而不会致使反序列化错误,即先解析 O:1:"B":0:{} 生成一个对象,而后在向后解析又遇到 i:0 因而将前一个 i:0 的值改成1,就至关于消灭了以前生成的对象因而触发__destruct函数,以后也是冗余的关系使得反序列化的结果返回的是 array(0=>1) ,不为False,因而不会进入到ob_end_clean(),最后输出flag
这题若是直接传入
O:1:"B":0:{}
是不会输出flag,由于虽然这样反序列化获得的a是一个对象不等于False,可是以后会经过throw new 抛出一个错误,它这里的抛出错误就相似于下了一个断点同样,使得脚本程序的运行中止在了这里,并无结束,因此反序列化后的B对象仍然存在,不会触发__destruct